diff --git a/app/my_app/.gitignore b/app/my_app/.gitignore new file mode 100644 index 000000000..24476c5d1 --- /dev/null +++ b/app/my_app/.gitignore @@ -0,0 +1,44 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/app/my_app/.metadata b/app/my_app/.metadata new file mode 100644 index 000000000..30d90a7ef --- /dev/null +++ b/app/my_app/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled. + +version: + revision: 796c8ef79279f9c774545b3771238c3098dbefab + channel: stable + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: android + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: ios + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: linux + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: macos + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: web + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: windows + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/app/my_app/.vscode/launch.json b/app/my_app/.vscode/launch.json new file mode 100644 index 000000000..aa4d45695 --- /dev/null +++ b/app/my_app/.vscode/launch.json @@ -0,0 +1,25 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "my_app", + "request": "launch", + "type": "dart" + }, + { + "name": "my_app (profile mode)", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + }, + { + "name": "my_app (release mode)", + "request": "launch", + "type": "dart", + "flutterMode": "release" + } + ] +} \ No newline at end of file diff --git a/app/my_app/.vscode/settings.json b/app/my_app/.vscode/settings.json new file mode 100644 index 000000000..cad7657df --- /dev/null +++ b/app/my_app/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cmake.configureOnOpen": false +} \ No newline at end of file diff --git a/app/my_app/README.md b/app/my_app/README.md new file mode 100644 index 000000000..103dec2c5 --- /dev/null +++ b/app/my_app/README.md @@ -0,0 +1,16 @@ +# my_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/app/my_app/analysis_options.yaml b/app/my_app/analysis_options.yaml new file mode 100644 index 000000000..758a51f60 --- /dev/null +++ b/app/my_app/analysis_options.yaml @@ -0,0 +1,10 @@ +include: package:flutter_lints/flutter.yaml + +linter: + rules: + prefer_const_constructors: false + prefer_final_fields: false + use_key_in_widget_constructors: false + prefer_const_literals_to_create_immutables: false + prefer_const_constructors_in_immutables: false + avoid_print: false \ No newline at end of file diff --git a/app/my_app/android/.gitignore b/app/my_app/android/.gitignore new file mode 100644 index 000000000..6f568019d --- /dev/null +++ b/app/my_app/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/app/my_app/android/app/build.gradle b/app/my_app/android/app/build.gradle new file mode 100644 index 000000000..6b6e158ab --- /dev/null +++ b/app/my_app/android/app/build.gradle @@ -0,0 +1,72 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + namespace "com.example.my_app" + compileSdkVersion flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.my_app" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. + minSdkVersion flutter.minSdkVersion + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/app/my_app/android/app/src/debug/AndroidManifest.xml b/app/my_app/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 000000000..399f6981d --- /dev/null +++ b/app/my_app/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/app/my_app/android/app/src/main/AndroidManifest.xml b/app/my_app/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..998e323d2 --- /dev/null +++ b/app/my_app/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + diff --git a/app/my_app/android/app/src/main/kotlin/com/example/my_app/MainActivity.kt b/app/my_app/android/app/src/main/kotlin/com/example/my_app/MainActivity.kt new file mode 100644 index 000000000..bab1d2fa1 --- /dev/null +++ b/app/my_app/android/app/src/main/kotlin/com/example/my_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.my_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/app/my_app/android/app/src/main/res/drawable-v21/launch_background.xml b/app/my_app/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 000000000..f74085f3f --- /dev/null +++ b/app/my_app/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/app/my_app/android/app/src/main/res/drawable/launch_background.xml b/app/my_app/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 000000000..304732f88 --- /dev/null +++ b/app/my_app/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/app/my_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/my_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..db77bb4b7 Binary files /dev/null and b/app/my_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/my_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/my_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..17987b79b Binary files /dev/null and b/app/my_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/my_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/my_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..09d439148 Binary files /dev/null and b/app/my_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/my_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/my_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..d5f1c8d34 Binary files /dev/null and b/app/my_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/my_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/my_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..4d6372eeb Binary files /dev/null and b/app/my_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/my_app/android/app/src/main/res/values-night/styles.xml b/app/my_app/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 000000000..06952be74 --- /dev/null +++ b/app/my_app/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/app/my_app/android/app/src/main/res/values/styles.xml b/app/my_app/android/app/src/main/res/values/styles.xml new file mode 100644 index 000000000..cb1ef8805 --- /dev/null +++ b/app/my_app/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/app/my_app/android/app/src/profile/AndroidManifest.xml b/app/my_app/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 000000000..399f6981d --- /dev/null +++ b/app/my_app/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/app/my_app/android/build.gradle b/app/my_app/android/build.gradle new file mode 100644 index 000000000..f7eb7f63c --- /dev/null +++ b/app/my_app/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.7.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.3.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/app/my_app/android/gradle.properties b/app/my_app/android/gradle.properties new file mode 100644 index 000000000..94adc3a3f --- /dev/null +++ b/app/my_app/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/app/my_app/android/gradle/wrapper/gradle-wrapper.properties b/app/my_app/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..3c472b99c --- /dev/null +++ b/app/my_app/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip diff --git a/app/my_app/android/settings.gradle b/app/my_app/android/settings.gradle new file mode 100644 index 000000000..44e62bcf0 --- /dev/null +++ b/app/my_app/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/app/my_app/assets/images/0000.png b/app/my_app/assets/images/0000.png new file mode 100644 index 000000000..8889b72a4 Binary files /dev/null and b/app/my_app/assets/images/0000.png differ diff --git a/app/my_app/assets/images/0001.png b/app/my_app/assets/images/0001.png new file mode 100644 index 000000000..c149d676c Binary files /dev/null and b/app/my_app/assets/images/0001.png differ diff --git a/app/my_app/assets/images/adv.png b/app/my_app/assets/images/adv.png new file mode 100644 index 000000000..e755e38df Binary files /dev/null and b/app/my_app/assets/images/adv.png differ diff --git a/app/my_app/ios/.gitignore b/app/my_app/ios/.gitignore new file mode 100644 index 000000000..7a7f9873a --- /dev/null +++ b/app/my_app/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/app/my_app/ios/Flutter/AppFrameworkInfo.plist b/app/my_app/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 000000000..9625e105d --- /dev/null +++ b/app/my_app/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 11.0 + + diff --git a/app/my_app/ios/Flutter/Debug.xcconfig b/app/my_app/ios/Flutter/Debug.xcconfig new file mode 100644 index 000000000..592ceee85 --- /dev/null +++ b/app/my_app/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/app/my_app/ios/Flutter/Release.xcconfig b/app/my_app/ios/Flutter/Release.xcconfig new file mode 100644 index 000000000..592ceee85 --- /dev/null +++ b/app/my_app/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/app/my_app/ios/Runner.xcodeproj/project.pbxproj b/app/my_app/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 000000000..ec99263d8 --- /dev/null +++ b/app/my_app/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,613 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807E294A63A400263BE5 /* Frameworks */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.myApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AE0B7B92F70575B8D7E0D07E /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.myApp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 89B67EB44CE7B6631473024E /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.myApp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 640959BDD8F10B91D80A66BE /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.myApp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.myApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.myApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/app/my_app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/app/my_app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/app/my_app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/app/my_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/app/my_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/app/my_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/app/my_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/app/my_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..f9b0d7c5e --- /dev/null +++ b/app/my_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/app/my_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/app/my_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 000000000..e42adcb34 --- /dev/null +++ b/app/my_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/my_app/ios/Runner.xcworkspace/contents.xcworkspacedata b/app/my_app/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..1d526a16e --- /dev/null +++ b/app/my_app/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/app/my_app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/app/my_app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/app/my_app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/app/my_app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/app/my_app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..f9b0d7c5e --- /dev/null +++ b/app/my_app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/app/my_app/ios/Runner/AppDelegate.swift b/app/my_app/ios/Runner/AppDelegate.swift new file mode 100644 index 000000000..70693e4a8 --- /dev/null +++ b/app/my_app/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..d36b1fab2 --- /dev/null +++ b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 000000000..dc9ada472 Binary files /dev/null and b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 000000000..7353c41ec Binary files /dev/null and b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 000000000..797d452e4 Binary files /dev/null and b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 000000000..6ed2d933e Binary files /dev/null and b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 000000000..4cd7b0099 Binary files /dev/null and b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 000000000..fe730945a Binary files /dev/null and b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 000000000..321773cd8 Binary files /dev/null and b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 000000000..797d452e4 Binary files /dev/null and b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 000000000..502f463a9 Binary files /dev/null and b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 000000000..0ec303439 Binary files /dev/null and b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 000000000..0ec303439 Binary files /dev/null and b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 000000000..e9f5fea27 Binary files /dev/null and b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 000000000..84ac32ae7 Binary files /dev/null and b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 000000000..8953cba09 Binary files /dev/null and b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 000000000..0467bf12a Binary files /dev/null and b/app/my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/app/my_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/app/my_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 000000000..0bedcf2fd --- /dev/null +++ b/app/my_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/app/my_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/app/my_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 000000000..9da19eaca Binary files /dev/null and b/app/my_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/app/my_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/app/my_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 000000000..9da19eaca Binary files /dev/null and b/app/my_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/app/my_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/app/my_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 000000000..9da19eaca Binary files /dev/null and b/app/my_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/app/my_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/app/my_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 000000000..89c2725b7 --- /dev/null +++ b/app/my_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/app/my_app/ios/Runner/Base.lproj/LaunchScreen.storyboard b/app/my_app/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 000000000..f2e259c7c --- /dev/null +++ b/app/my_app/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/my_app/ios/Runner/Base.lproj/Main.storyboard b/app/my_app/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 000000000..f3c28516f --- /dev/null +++ b/app/my_app/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/my_app/ios/Runner/Info.plist b/app/my_app/ios/Runner/Info.plist new file mode 100644 index 000000000..3c940b6dc --- /dev/null +++ b/app/my_app/ios/Runner/Info.plist @@ -0,0 +1,51 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + My App + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + my_app + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/app/my_app/ios/Runner/Runner-Bridging-Header.h b/app/my_app/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 000000000..308a2a560 --- /dev/null +++ b/app/my_app/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/app/my_app/ios/RunnerTests/RunnerTests.swift b/app/my_app/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 000000000..86a7c3b1b --- /dev/null +++ b/app/my_app/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/app/my_app/lib/main.dart b/app/my_app/lib/main.dart new file mode 100644 index 000000000..63cebf943 --- /dev/null +++ b/app/my_app/lib/main.dart @@ -0,0 +1,685 @@ +// import 'package:english_words/english_words.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:http/http.dart' as http; +import 'dart:async'; +import 'dart:convert'; + +Future fetchAlbum() async { + final response = await http + .get(Uri.parse('https://marketplace-1-b3203472.deta.app/search/featured')); + + if (response.statusCode == 200) { + // If the server did return a 200 OK response, + // then parse the JSON. + return Album.fromJson(jsonDecode(response.body)); + } else { + // If the server did not return a 200 OK response, + // then throw an exception. + throw Exception('Failed to load album'); + } +} + +class Album { + final String id; + final String title; + final String category; + final int price; + final String location; + final String description; + final bool isNegotiable; + final bool isFeatured; + final bool isPromoted; + + const Album({ + required this.id, + required this.title, + required this.category , + required this.price , + required this.location , + required this.description , + required this.isNegotiable , + required this.isFeatured , + required this.isPromoted , + }); +//continue here: change map to list..... +//Because our sources are of list type rather than map type... + factory Album.fromJson(List json) { + return Album( + id: json['_id'], + title: json['title'], + category: json['category'], + price: json['price'], + location: json['location'], + description: json['description'], + isNegotiable: json['isNegotiable'], + isFeatured: json['isFeatured'], + isPromoted: json['isPromoted'], + ); + } +} + +void main() { + runApp(MyApp()); +} + +class MyApp extends StatefulWidget { + const MyApp({super.key}); + + @override + State createState() => _MyAppState(); +} + +class _MyAppState extends State { + late Future futureAlbum; + + @override + void initState() { + super.initState(); + futureAlbum = fetchAlbum(); + } + + @override + Widget build(BuildContext context) { + var appState = context.watch(); + return ChangeNotifierProvider( + create: (context) => MyAppState(), + child: MaterialApp( + title: 'Namer App', + theme: ThemeData( + useMaterial3: true, + colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue), + ), + home: Scaffold( + appBar: AppBar( + title: const Text('Fetch Data Example'), + ), + body: Center( + child: FutureBuilder( + future: futureAlbum, + builder: (context, snapshot) { + if (snapshot.hasData) { + return Text(snapshot.data!.title); + } else if (snapshot.hasError) { + print('cannot fetch data'); + return MyHomePage(); + } + + // By default, show a loading spinner. + return const CircularProgressIndicator(); + }, + ), + ), + ), + ), + ); + } +} + +class MyAppState extends ChangeNotifier { + var currentProduct = -1; + void getproduct(var prd) { + currentProduct = prd; + notifyListeners(); + } + + var cart = []; + void toggleCart(var input) { + if (cart.contains(input)) { + cart.remove(input); + } else { + cart.add(input); + } + notifyListeners(); + } + + var wishlist = []; + void toggleWishList(var input) { + if (wishlist.contains(input)) { + wishlist.remove(input); + } else { + wishlist.add(input); + } + notifyListeners(); + } + + var products = [ + ["Title", "Description", "Price", 'assets/images/0000.png'], + ["Title", "Description", "Price", 'assets/images/0000.png'], + ["Title", "Description", "Price", 'assets/images/0000.png'], + ["title", "Des", "Price", "assets/images/0001.png"], + ["title", "Des", "Price", "assets/images/0001.png"], + ["title", "Des", "Price", "assets/images/0001.png"], + ["title", "Des", "Price", "assets/images/0001.png"] + ]; + + var featuredProducts = [0, 1, 2, 5]; +} + +class MyHomePage extends StatefulWidget { + @override + State createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + var selectedIndex = 0; + + @override + Widget build(BuildContext context) { + var appState = context.watch(); + Widget page; + switch (selectedIndex) { + case 0: + page = GeneratorPage(); + break; + case 1: + page = CartPage(); + break; + case 2: + page = WishListPage(); + break; + case 3: + page = ListProductPage(); + break; + default: + throw UnimplementedError('no widget for $selectedIndex'); + } + void onItemTapped(int index) { + setState(() { + selectedIndex = index; + appState.getproduct(-1); + }); + } + + return LayoutBuilder(builder: (context, constraints) { + return Scaffold( + appBar: AppBar( + title: const Text('Daymarket: Solution to everything.'), + ), + body: Column( + children: [ + Expanded( + child: Container( + color: Theme.of(context).colorScheme.primaryContainer, + child: page, + ), + ), + ], + ), + bottomNavigationBar: BottomNavigationBar( + items: const [ + BottomNavigationBarItem( + icon: Icon(Icons.home), + label: 'Home', + ), + BottomNavigationBarItem( + icon: Icon(Icons.shopping_cart), + label: 'Cart', + ), + BottomNavigationBarItem( + icon: Icon(Icons.favorite_border_outlined), + label: 'Wishlist', + ), + BottomNavigationBarItem( + icon: Icon(Icons.sell), + label: 'Sell', + ), + ], + currentIndex: selectedIndex, + selectedItemColor: Theme.of(context).colorScheme.primary, + unselectedItemColor: Theme.of(context).colorScheme.secondary, + onTap: onItemTapped, + ), + ); + }); + } +} + +class GeneratorPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + var appState = context.watch(); + // var pair = appState.current; + + // IconData icon; + // if (appState.favorites.contains(pair)) { + // icon = Icons.favorite; + // } else { + // icon = Icons.favorite_border; + // } + if (appState.currentProduct == -1) { + return Scaffold( + body: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + BigCard(), + SizedBox(height: 10), + SizedBox(height: 150, child: BannerView()), + SizedBox( + height: 200.0, + child: ListView.builder( + physics: ClampingScrollPhysics(), + shrinkWrap: true, + scrollDirection: Axis.horizontal, + itemCount: appState.featuredProducts.length, + itemBuilder: (BuildContext context, int index) => Card( + child: GestureDetector( + onTap: () { + appState.getproduct(appState.featuredProducts[index]); + }, + child: SizedBox( + width: 120, + height: 100, + child: Column( + children: [ + Stack( + children: [ + Container( + decoration: + BoxDecoration(color: Colors.white), + alignment: Alignment.center, + height: 100, + child: Image.asset( + appState.products[ + appState.featuredProducts[index]][3], + height: 100, + width: 100, + ), + ), + Align( + alignment: Alignment.topRight, + child: TextButton( + onPressed: () { + appState.toggleWishList( + appState.featuredProducts[index]); + }, + child: ((appState.wishlist.contains( + appState.featuredProducts[ + index])) == + true) + ? Icon(Icons.favorite) + : Icon( + Icons.favorite_border_outlined)), + ) + ], + ), + Text(appState + .products[appState.featuredProducts[index]][0]), + Text(appState + .products[appState.featuredProducts[index]][1]), + Text(appState + .products[appState.featuredProducts[index]][2]), + ], + ), + ), + ), + ), + ), + ), + for (var i = 0; i < appState.products.length; i++) + Padding( + padding: const EdgeInsets.all(8.0), + child: ElevatedButton( + onPressed: () { + appState.getproduct(i); + }, + child: Row(children: [ + Image.asset( + appState.products[i][3], + height: 50, + width: 50, + ), + Column( + children: [ + Row( + children: [ + Text(appState.products[i][0]), + Text(appState.products[i][2]), + ], + ), + Text(appState.products[i][1]) + ], + ) + ]), + ), + ), + ], + ), + ), + ); + } else { + return ProductPage(); + } + } +} + +class BigCard extends StatelessWidget { + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final style = theme.textTheme.displayMedium!.copyWith( + color: theme.colorScheme.onPrimary, + ); + return Card( + color: theme.colorScheme.primary, + child: Padding( + padding: const EdgeInsets.all(20), + child: Text( + "DayMarket", + style: style, + ), + ), + ); + } +} + +class BannerView extends StatelessWidget { + @override + Widget build(BuildContext context) { + // final theme = Theme.of(context); + // final style = theme.textTheme.displayMedium!.copyWith( + // color: theme.colorScheme.onPrimary, + // ); + final PageController controller = PageController(); + return PageView( + /// [PageView.scrollDirection] defaults to [Axis.horizontal]. + /// Use [Axis.vertical] to scroll vertically. + controller: controller, + children: [ + Image.asset( + 'assets/images/adv.png', + height: 70, + fit: BoxFit.cover, + ), + Image.asset( + 'assets/images/adv.png', + height: 70, + fit: BoxFit.cover, + ), + Image.asset( + 'assets/images/adv.png', + height: 70, + fit: BoxFit.cover, + ), + ], + ); + } +} + +class ProductPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + var appState = context.watch(); + var products = appState.products; + var currentProduct = appState.currentProduct; + var addOrRemoveCart = "Hell"; + var addOrRemoveWish = "Hell"; + if (appState.cart.contains(currentProduct)) { + addOrRemoveCart = "Remove From Cart"; + } else { + addOrRemoveCart = "Add To Cart"; + } + if (appState.wishlist.contains(currentProduct)) { + addOrRemoveWish = "Remove From Wishlist"; + } else { + addOrRemoveWish = "Add To Wishlist"; + } + return Column( + children: [ + Image.asset(appState.products[currentProduct][3]), + Text(products[currentProduct][0]), + Text(products[currentProduct][1]), + Text(products[currentProduct][2]), + ElevatedButton( + onPressed: () { + appState.toggleCart(currentProduct); + }, + child: Text(addOrRemoveCart)), + ElevatedButton( + onPressed: () { + appState.toggleWishList(currentProduct); + }, + child: Text(addOrRemoveWish)), + ], + ); + } +} + +class CartPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + var appState = context.watch(); + + if (appState.cart.isEmpty) { + return Center( + child: Text('No items added yet.'), + ); + } + return ListView( + children: [ + Padding( + padding: const EdgeInsets.all(20), + child: Text('You have ' + '${appState.cart.length} item in cart:'), + ), + for (var pair in appState.cart) + Row( + children: [ + Image.asset( + appState.products[pair][3], + height: 50, + width: 50, + ), + Text(appState.products[pair][0]), + ElevatedButton( + onPressed: () { + appState.toggleCart(pair); + }, + child: Text("Remove")), + ], + ), + ], + ); + } +} + +class WishListPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + var appState = context.watch(); + + if (appState.wishlist.isEmpty) { + return Center( + child: Text('Your wishlist is empty now.'), + ); + } + return ListView( + children: [ + Padding( + padding: const EdgeInsets.all(20), + child: Text('You have ' + '${appState.wishlist.length} wishes:'), + ), + for (var pair in appState.wishlist) + Row( + children: [ + Image.asset( + appState.products[pair][3], + height: 50, + width: 50, + ), + Text(appState.products[pair][0]), + ElevatedButton( + onPressed: () { + appState.toggleWishList(pair); + }, + child: Text("Remove")), + ], + ), + ], + ); + } +} + +class ListProductPage extends StatefulWidget { + @override + State createState() => _ListProductPageState(); +} + +class _ListProductPageState extends State { + bool negotiable = false; + + @override + Widget build(BuildContext context) { + final formKey = GlobalKey(); + + // Build a Form widget using the _formKey created above. + return Form( + key: formKey, + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Text('Submit the form to sell your product!...'), + ), + Column( + children: [ + Text('Title : '), + SizedBox( + width: 150, + child: TextFormField( + decoration: InputDecoration( + border: OutlineInputBorder(), + hintText: 'Wingardium Leviosa'), + // The validator receives the text that the user has entered. + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter some text'; + } + return null; + }, + ), + ), + ], + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + children: [ + Text('Category : '), + SizedBox( + width: 150, + child: TextFormField( + decoration: InputDecoration( + border: OutlineInputBorder(), + hintText: 'Wingardium Leviosa'), + // The validator receives the text that the user has entered. + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter some text'; + } + return null; + }, + ), + ), + ], + ), + Column( + children: [ + Text('Price : '), + SizedBox( + width: 150, + child: TextFormField( + decoration: InputDecoration( + border: OutlineInputBorder(), hintText: 'Rs. '), + // The validator receives the text that the user has entered. + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter some text'; + } + return null; + }, + ), + ), + ], + ), + ], + ), + ), + Column( + children: [ + Text('Location : '), + SizedBox( + width: 150, + child: TextFormField( + decoration: InputDecoration( + border: OutlineInputBorder(), hintText: 'Hogwarts'), + // The validator receives the text that the user has entered. + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter some text'; + } + return null; + }, + ), + ), + ], + ), + Column( + children: [ + Text('Description : '), + SizedBox( + width: MediaQuery.of(context).size.width * 0.80, + child: TextFormField( + decoration: InputDecoration( + border: OutlineInputBorder(), + hintText: 'A series of magic...'), + // The validator receives the text that the user has entered. + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter some text'; + } + return null; + }, + ), + ), + ], + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Text('Is the price negotiable ? '), + Switch( + value: negotiable, // watch the ! + onChanged: (bool val) => setState( + () { + negotiable = val; + }, + ), + ), + ], + ), + ), + ElevatedButton( + onPressed: () { + // Validate returns true if the form is valid, or false otherwise. + if (formKey.currentState!.validate()) { + // If the form is valid, display a snackbar. In the real world, + // you'd often call a server or save the information in a database. + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Processing Data')), + ); + } + }, + child: const Text('Submit'), + ), + ], + ), + ); + } +} diff --git a/app/my_app/linux/.gitignore b/app/my_app/linux/.gitignore new file mode 100644 index 000000000..d3896c984 --- /dev/null +++ b/app/my_app/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/app/my_app/linux/CMakeLists.txt b/app/my_app/linux/CMakeLists.txt new file mode 100644 index 000000000..88f1560b4 --- /dev/null +++ b/app/my_app/linux/CMakeLists.txt @@ -0,0 +1,139 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "my_app") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.my_app") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Define the application target. To change its name, change BINARY_NAME above, +# not the value here, or `flutter run` will no longer work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/app/my_app/linux/flutter/CMakeLists.txt b/app/my_app/linux/flutter/CMakeLists.txt new file mode 100644 index 000000000..d5bd01648 --- /dev/null +++ b/app/my_app/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/app/my_app/linux/flutter/generated_plugin_registrant.cc b/app/my_app/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000..e71a16d23 --- /dev/null +++ b/app/my_app/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/app/my_app/linux/flutter/generated_plugin_registrant.h b/app/my_app/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000..e0f0a47bc --- /dev/null +++ b/app/my_app/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/app/my_app/linux/flutter/generated_plugins.cmake b/app/my_app/linux/flutter/generated_plugins.cmake new file mode 100644 index 000000000..2e1de87a7 --- /dev/null +++ b/app/my_app/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/app/my_app/linux/main.cc b/app/my_app/linux/main.cc new file mode 100644 index 000000000..e7c5c5437 --- /dev/null +++ b/app/my_app/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/app/my_app/linux/my_application.cc b/app/my_app/linux/my_application.cc new file mode 100644 index 000000000..2ac6dea28 --- /dev/null +++ b/app/my_app/linux/my_application.cc @@ -0,0 +1,104 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "my_app"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "my_app"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/app/my_app/linux/my_application.h b/app/my_app/linux/my_application.h new file mode 100644 index 000000000..72271d5e4 --- /dev/null +++ b/app/my_app/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/app/my_app/macos/.gitignore b/app/my_app/macos/.gitignore new file mode 100644 index 000000000..746adbb6b --- /dev/null +++ b/app/my_app/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/app/my_app/macos/Flutter/Flutter-Debug.xcconfig b/app/my_app/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 000000000..c2efd0b60 --- /dev/null +++ b/app/my_app/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1 @@ +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/app/my_app/macos/Flutter/Flutter-Release.xcconfig b/app/my_app/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 000000000..c2efd0b60 --- /dev/null +++ b/app/my_app/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1 @@ +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/app/my_app/macos/Flutter/GeneratedPluginRegistrant.swift b/app/my_app/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 000000000..cccf817a5 --- /dev/null +++ b/app/my_app/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,10 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { +} diff --git a/app/my_app/macos/Runner.xcodeproj/project.pbxproj b/app/my_app/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 000000000..71430d686 --- /dev/null +++ b/app/my_app/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,695 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* my_app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "my_app.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* my_app.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* my_app.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.myApp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/my_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/my_app"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.myApp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/my_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/my_app"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.myApp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/my_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/my_app"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/app/my_app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/app/my_app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/app/my_app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/app/my_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/app/my_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 000000000..1006d14fb --- /dev/null +++ b/app/my_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/my_app/macos/Runner.xcworkspace/contents.xcworkspacedata b/app/my_app/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..1d526a16e --- /dev/null +++ b/app/my_app/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/app/my_app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/app/my_app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/app/my_app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/app/my_app/macos/Runner/AppDelegate.swift b/app/my_app/macos/Runner/AppDelegate.swift new file mode 100644 index 000000000..d53ef6437 --- /dev/null +++ b/app/my_app/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..a2ec33f19 --- /dev/null +++ b/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 000000000..82b6f9d9a Binary files /dev/null and b/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 000000000..13b35eba5 Binary files /dev/null and b/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 000000000..0a3f5fa40 Binary files /dev/null and b/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 000000000..bdb57226d Binary files /dev/null and b/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 000000000..f083318e0 Binary files /dev/null and b/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 000000000..326c0e72c Binary files /dev/null and b/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 000000000..2f1632cfd Binary files /dev/null and b/app/my_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/app/my_app/macos/Runner/Base.lproj/MainMenu.xib b/app/my_app/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 000000000..80e867a4e --- /dev/null +++ b/app/my_app/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/my_app/macos/Runner/Configs/AppInfo.xcconfig b/app/my_app/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 000000000..79236bc65 --- /dev/null +++ b/app/my_app/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = my_app + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.myApp + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved. diff --git a/app/my_app/macos/Runner/Configs/Debug.xcconfig b/app/my_app/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 000000000..36b0fd946 --- /dev/null +++ b/app/my_app/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/app/my_app/macos/Runner/Configs/Release.xcconfig b/app/my_app/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 000000000..dff4f4956 --- /dev/null +++ b/app/my_app/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/app/my_app/macos/Runner/Configs/Warnings.xcconfig b/app/my_app/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 000000000..42bcbf478 --- /dev/null +++ b/app/my_app/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/app/my_app/macos/Runner/DebugProfile.entitlements b/app/my_app/macos/Runner/DebugProfile.entitlements new file mode 100644 index 000000000..dddb8a30c --- /dev/null +++ b/app/my_app/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/app/my_app/macos/Runner/Info.plist b/app/my_app/macos/Runner/Info.plist new file mode 100644 index 000000000..4789daa6a --- /dev/null +++ b/app/my_app/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/app/my_app/macos/Runner/MainFlutterWindow.swift b/app/my_app/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 000000000..3cc05eb23 --- /dev/null +++ b/app/my_app/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/app/my_app/macos/Runner/Release.entitlements b/app/my_app/macos/Runner/Release.entitlements new file mode 100644 index 000000000..852fa1a47 --- /dev/null +++ b/app/my_app/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/app/my_app/macos/RunnerTests/RunnerTests.swift b/app/my_app/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 000000000..5418c9f53 --- /dev/null +++ b/app/my_app/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import FlutterMacOS +import Cocoa +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/app/my_app/pubspec.lock b/app/my_app/pubspec.lock new file mode 100644 index 000000000..4a7b6c5b5 --- /dev/null +++ b/app/my_app/pubspec.lock @@ -0,0 +1,229 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + url: "https://pub.dev" + source: hosted + version: "1.17.1" + english_words: + dependency: "direct main" + description: + name: english_words + sha256: "6a7ef6473a97bd8571b6b641d006a6e58a7c67e65fb6f3d6d1151cb46b0e983c" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + http: + dependency: "direct main" + description: + name: http + sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + lints: + dependency: transitive + description: + name: lints + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + url: "https://pub.dev" + source: hosted + version: "0.12.15" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" + source: hosted + version: "0.2.0" + meta: + dependency: transitive + description: + name: meta + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + path: + dependency: transitive + description: + name: path + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" + source: hosted + version: "1.8.3" + provider: + dependency: "direct main" + description: + name: provider + sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f + url: "https://pub.dev" + source: hosted + version: "6.0.5" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" + source: hosted + version: "1.9.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + url: "https://pub.dev" + source: hosted + version: "0.5.1" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" +sdks: + dart: ">=3.0.0 <4.0.0" + flutter: ">=1.16.0" diff --git a/app/my_app/pubspec.yaml b/app/my_app/pubspec.yaml new file mode 100644 index 000000000..3afe86618 --- /dev/null +++ b/app/my_app/pubspec.yaml @@ -0,0 +1,29 @@ +name: my_app +description: A new Flutter project. + +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +version: 0.0.1+1 + +environment: + sdk: '>=2.19.4 <4.0.0' + +dependencies: + flutter: + sdk: flutter + + english_words: ^4.0.0 + provider: ^6.0.0 + http: ^1.1.0 + +dev_dependencies: + flutter_test: + sdk: flutter + + flutter_lints: ^2.0.0 + +flutter: + uses-material-design: true + assets: + - assets/images/ + diff --git a/app/my_app/test/widget_test.dart b/app/my_app/test/widget_test.dart new file mode 100644 index 000000000..f23f0964a --- /dev/null +++ b/app/my_app/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:my_app/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/app/my_app/web/favicon.png b/app/my_app/web/favicon.png new file mode 100644 index 000000000..8aaa46ac1 Binary files /dev/null and b/app/my_app/web/favicon.png differ diff --git a/app/my_app/web/icons/Icon-192.png b/app/my_app/web/icons/Icon-192.png new file mode 100644 index 000000000..b749bfef0 Binary files /dev/null and b/app/my_app/web/icons/Icon-192.png differ diff --git a/app/my_app/web/icons/Icon-512.png b/app/my_app/web/icons/Icon-512.png new file mode 100644 index 000000000..88cfd48df Binary files /dev/null and b/app/my_app/web/icons/Icon-512.png differ diff --git a/app/my_app/web/icons/Icon-maskable-192.png b/app/my_app/web/icons/Icon-maskable-192.png new file mode 100644 index 000000000..eb9b4d76e Binary files /dev/null and b/app/my_app/web/icons/Icon-maskable-192.png differ diff --git a/app/my_app/web/icons/Icon-maskable-512.png b/app/my_app/web/icons/Icon-maskable-512.png new file mode 100644 index 000000000..d69c56691 Binary files /dev/null and b/app/my_app/web/icons/Icon-maskable-512.png differ diff --git a/app/my_app/web/index.html b/app/my_app/web/index.html new file mode 100644 index 000000000..4465d7185 --- /dev/null +++ b/app/my_app/web/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + my_app + + + + + + + + + + diff --git a/app/my_app/web/manifest.json b/app/my_app/web/manifest.json new file mode 100644 index 000000000..9af4bfde3 --- /dev/null +++ b/app/my_app/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "my_app", + "short_name": "my_app", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/app/my_app/windows/.gitignore b/app/my_app/windows/.gitignore new file mode 100644 index 000000000..d492d0d98 --- /dev/null +++ b/app/my_app/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/app/my_app/windows/CMakeLists.txt b/app/my_app/windows/CMakeLists.txt new file mode 100644 index 000000000..1fa8548c3 --- /dev/null +++ b/app/my_app/windows/CMakeLists.txt @@ -0,0 +1,102 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(my_app LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "my_app") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/app/my_app/windows/flutter/CMakeLists.txt b/app/my_app/windows/flutter/CMakeLists.txt new file mode 100644 index 000000000..930d2071a --- /dev/null +++ b/app/my_app/windows/flutter/CMakeLists.txt @@ -0,0 +1,104 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + windows-x64 $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/app/my_app/windows/flutter/generated_plugin_registrant.cc b/app/my_app/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000..8b6d4680a --- /dev/null +++ b/app/my_app/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/app/my_app/windows/flutter/generated_plugin_registrant.h b/app/my_app/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000..dc139d85a --- /dev/null +++ b/app/my_app/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/app/my_app/windows/flutter/generated_plugins.cmake b/app/my_app/windows/flutter/generated_plugins.cmake new file mode 100644 index 000000000..b93c4c30c --- /dev/null +++ b/app/my_app/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/app/my_app/windows/runner/CMakeLists.txt b/app/my_app/windows/runner/CMakeLists.txt new file mode 100644 index 000000000..394917c05 --- /dev/null +++ b/app/my_app/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/app/my_app/windows/runner/Runner.rc b/app/my_app/windows/runner/Runner.rc new file mode 100644 index 000000000..619f063d1 --- /dev/null +++ b/app/my_app/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "my_app" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "my_app" "\0" + VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "my_app.exe" "\0" + VALUE "ProductName", "my_app" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/app/my_app/windows/runner/flutter_window.cpp b/app/my_app/windows/runner/flutter_window.cpp new file mode 100644 index 000000000..b25e363ef --- /dev/null +++ b/app/my_app/windows/runner/flutter_window.cpp @@ -0,0 +1,66 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/app/my_app/windows/runner/flutter_window.h b/app/my_app/windows/runner/flutter_window.h new file mode 100644 index 000000000..6da0652f0 --- /dev/null +++ b/app/my_app/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/app/my_app/windows/runner/main.cpp b/app/my_app/windows/runner/main.cpp new file mode 100644 index 000000000..7311fe8fa --- /dev/null +++ b/app/my_app/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"my_app", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/app/my_app/windows/runner/resource.h b/app/my_app/windows/runner/resource.h new file mode 100644 index 000000000..66a65d1e4 --- /dev/null +++ b/app/my_app/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/app/my_app/windows/runner/resources/app_icon.ico b/app/my_app/windows/runner/resources/app_icon.ico new file mode 100644 index 000000000..c04e20caf Binary files /dev/null and b/app/my_app/windows/runner/resources/app_icon.ico differ diff --git a/app/my_app/windows/runner/runner.exe.manifest b/app/my_app/windows/runner/runner.exe.manifest new file mode 100644 index 000000000..a42ea7687 --- /dev/null +++ b/app/my_app/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/app/my_app/windows/runner/utils.cpp b/app/my_app/windows/runner/utils.cpp new file mode 100644 index 000000000..b2b08734d --- /dev/null +++ b/app/my_app/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length <= 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/app/my_app/windows/runner/utils.h b/app/my_app/windows/runner/utils.h new file mode 100644 index 000000000..3879d5475 --- /dev/null +++ b/app/my_app/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/app/my_app/windows/runner/win32_window.cpp b/app/my_app/windows/runner/win32_window.cpp new file mode 100644 index 000000000..60608d0fe --- /dev/null +++ b/app/my_app/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/app/my_app/windows/runner/win32_window.h b/app/my_app/windows/runner/win32_window.h new file mode 100644 index 000000000..e901dde68 --- /dev/null +++ b/app/my_app/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/author.json b/author.json index 3d4a531ce..40c3d14c2 100644 --- a/author.json +++ b/author.json @@ -1,4 +1,4 @@ { - "name": "", - "entry_number": "" + "name": "Dinu Goyal", + "entry_number": "2022CS51647" } diff --git a/backend/.gitignore b/backend/.gitignore new file mode 100644 index 000000000..56a04c3cb --- /dev/null +++ b/backend/.gitignore @@ -0,0 +1,137 @@ +# Django # +*.log +*.pot +*.pyc +__pycache__ +db.sqlite3 +media + +# Backup files # +*.bak + +# If you are using PyCharm # +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# File-based project format +*.iws + +# IntelliJ +out/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Python # +*.py[cod] +*$py.class + +# Distribution / packaging +.Python build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +.pytest_cache/ +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery +celerybeat-schedule.* + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +# Sublime Text # +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache +*.sublime-workspace +*.sublime-project + +# sftp configuration file +sftp-config.json + +# Package control specific files Package +Control.last-run +Control.ca-list +Control.ca-bundle +Control.system-ca-bundle +GitHub.sublime-settings + +# Visual Studio Code # +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history \ No newline at end of file diff --git a/backend/week1/database.py b/backend/week1/database.py new file mode 100644 index 000000000..7fafa8e22 --- /dev/null +++ b/backend/week1/database.py @@ -0,0 +1,12 @@ +import sqlite3 +con = sqlite3.connect("redirect.db") +cur = con.cursor() +# res = cur.execute("insert into location values('aaaaa','https://google.com',0)") +# cur.execute("CREATE TABLE location(short CHAR(100),long CHAR(100),count INT)") +cur.execute("DELETE FROM location") +# cur.execute("DROP TABLE location") + +for row in cur.execute("select short,long,count from location"): + print(row) +print("executed") +con.commit() \ No newline at end of file diff --git a/backend/week1/redirect.db b/backend/week1/redirect.db new file mode 100644 index 000000000..9cd8c5bf9 Binary files /dev/null and b/backend/week1/redirect.db differ diff --git a/backend/week1/report.md b/backend/week1/report.md new file mode 100644 index 000000000..7c5df438a --- /dev/null +++ b/backend/week1/report.md @@ -0,0 +1,127 @@ +**MOODLE REPORT:** + +# + +![](media/4e1ba1d0c226e13672a44ad8e51125ab.png)**1. The webpage** looks as above: + +And the network console is like : + +![](media/32121791bd108e51f087dafa3ac365d6.png) + +The browser requests many different files like php, stylesheets, scripts, svgs and xmls. + +The requests are mainly initiated in index.php file: + +![](media/23318fbd9b87d70cf918fc220cc096ce.png) + +But after that the requests are also initiated in other files like script and all… + +Here we can see initiation of css files named moodlesimple-min.css, firstthemesheet and clean/all + +![](media/dc77d99f217350e8bd9d4306846dd227.png) + +Initiation of javascript docs… + +![](media/3390cef2cfc31f2b05dcb1a867a8ec6e.png) + +More script files: + +![](media/41f88db91586dd4c676f91be04101a49.png) + +Script for footer: + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +**2. Headers:** + +![](media/f5e0779cd2860950f382af7943c283f1.png) + +Status code refers to http response which is 200 showing successful response. + +Remote address probably refers to the port + +Referrer policy refers to whether url is sent full or only a part of it. + +Strict-origin-when-cross-origin offers more privacy. With this policy, only the origin is sent in the Referer header of cross-origin requests. This prevents leaks of private data that may be accessible from other parts of the full URL such as the path and query string. + +**Response headers** hold additional information about the response, like its location or about the server providing it. + +![](media/a7b3c3af3b3f1722daea52cb5b53e7ea.png) + +![](media/bd5cd88dd433302d1d96aaa26dd73ea6.png)The Cache-Control HTTP header field holds directives (instructions) — in both requests and responses — that control caching in browsers and shared caches (e.g. Proxies, CDNs). Private cache exists in the client. It is also called local cache or browser cache. It can store and reuse personalized content for a single user. The max-age=N response directive indicates that the response remains fresh until N seconds after the response is generated. Some intermediaries transform content for various reasons. For example, some convert images to reduce transfer size. In some cases, this is undesirable for the content provider. no-transform indicates that any intermediary (regardless of whether it implements a cache) shouldn't transform the response contents. + +Connection header is a hop by hop header and it should not be retransmitted by proxies or cached. The Keep-Alive general header allows the sender to hint about how the connection may be used to set a timeout and a maximum amount of requests. + +Content- Used to specify the compression algorithm, human language, size of resource(in bytes), type of resource. + +Expires The date/time after which the response is considered stale. + +Pragma Implementation-specific header that may have various effects anywhere along the request-response chain. Used for backwards compatibility with HTTP/1.0 caches where the Cache-Control header is not yet present. + +Vary Determines how to match request headers to decide whether a cached response can be used rather than requesting a fresh one from the origin server. + +**Request headers** contain more information about the resource to be fetched, or about the client requesting the resource. + +![](media/a38d5386f7293b9754f74c944e09a6a4.png) + +Sec-Fetch metadata request headers provide information about the context from which the request originated. A server can use them to make decisions about whether a request should be allowed, based on where the request came from and how the resource will be used. + +Sec-Fetch-Site is set to none because the request has not been made by a site. + +Sec-Fetch-User is set to 1 indicating that a navigation request was triggered by user navigation. + +Sec-Fetch-Dest is set to socument indicating requests destination. + +Cookie Contains stored HTTP cookies previously sent by the server with the Set-Cookie header. + +User-Agent Contains a characteristic string that allows the network protocol peers to identify the application type, operating system, software vendor or software version of the requesting software user agent. + +Representation or payload headers have not been used over here. + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +**3. Login to moodle:** + +Before: After: + +![](media/1e615b8ceb8ef2f44b459d2301c5b6a8.png)![](media/492b927ff9aec21bd640bab95efb6c67.png) + +After login to moodle the no. of requests went to 63 from 19 and it took 2s to finish. + +When we login to moodle, a POST request is initiated by index.html to the server and the server responds by giving a get redirect request. After that a plethora of resources are demanded by the index.html and others which result in issuing of new get requests. + +*Cookies* are small pieces of data that websites store on a user's web browser. They are a fundamental part of the communication between the web browser and the server and are often used for a variety of purposes, including authentication. Cookies allow a web server to remember and track information about a user's browsing activity, preferences, and state data. + +This is how cookies are used in communication and authentication between the browser and the server: + +Basic cookie mechanism: + +When a user visits a website, the web server may send a small HTTP header named "Set-Cookie" to the user's browser. This header contains data (cookies) that the browser stores locally. The browser will then include the cookie in all future requests to the same website, allowing the server to identify and recognize the user. + +Session cookies: + +Session cookies are temporary cookies that are stored in the browser's memory and are typically used to store session information. When the user closes the browser, the session cookie is usually deleted and the session ends. They are typically used to authenticate users during a browsing session. + +Persistent cookies: + +Persistent cookies have a specified expiration date and are stored on the user's device even after the browser is closed. They are used for a variety of purposes, such as remembering login information, tracking user preferences, and providing a personalized browsing experience. + +accuracy: + +Cookies play an important role in user authentication. When a user logs into a website, the server generates a unique ID or token (usually a session ID) that represents the authenticated session. This identifier is then stored in a cookie on the user's browser. The browser includes this cookie in each subsequent request to the server, allowing the server to identify the user and keep their session authenticated. Security vanity: + +Although cookies are widely used for authentication, they also raise security concerns. For example, if an attacker goes to a user's browser and extracts their authentication cookie, then they can impersonate the user without their credentials. To work around this, websites use various security measures such as HTTPS, secure flags on cookies, and token expiration to limit the risks associated with cookies. + +Same-origin policy: + +Cookies are subject to a "same-origin policy", which means that a website can only access cookies set by its own domain and not by other domains. This policy improves security by preventing different websites from accessing each other's data stored in cookies. In summary, cookies are essential for maintaining state information in browser-server communication and are widely used for user authentication, session management, and personalization on web pages. They enable a seamless and personalized user experience while requiring appropriate security measures to protect user data and privacy. + +BONUS TASKS : + +![](media/e7c3f49240a7673ca278a0511302fb8c.png) + +JSON Web Tokens (JWTs) are a type of token-based authentication that is commonly used in web applications. JWTs are compact and self-contained, making them an efficient way to transmit authentication information between parties. They consist of three parts separated by dots: the header, the payload, and the signature. + +Codeforces as a website does not use jwts as can be seen in the screenshot attached as there is no sign of a authorization header or a long string of text in the cookies. + +![](media/13e4ea18513357843b1fa382cc76a8e7.png) diff --git a/backend/week1/report.md.docx b/backend/week1/report.md.docx new file mode 100644 index 000000000..55d07fbae Binary files /dev/null and b/backend/week1/report.md.docx differ diff --git a/backend/week1/server.py b/backend/week1/server.py new file mode 100644 index 000000000..b4b632546 --- /dev/null +++ b/backend/week1/server.py @@ -0,0 +1,42 @@ +import http.server +import socketserver +import sqlite3 + +con = sqlite3.connect("redirect.db") +cur = con.cursor() + +port = 8000 +class myhandler(http.server.SimpleHTTPRequestHandler): + def do_GET(self): + self.send_response(302) + # print(self.headers) + print("Path was looking for : ",self.path) + for row in cur.execute("select short,long,count from location"): + if(row[0].lower() in self.path): + self.send_header('Location',row[1]) + self.send_header("Cache-Control","no-cache") + self.send_header("last-modified","Wed, 30 Nov 2022 00:00:00 GMT") + cur.execute("UPDATE location SET count = REPLACE(count,?,?) where short = ?;",[row[2],row[2]+1,row[0]]) + print("Now count is : ",row[2]) + con.commit() + break + self.end_headers() + + def do_POST(self): + self.send_response(201) + print("Path was looking for : ",self.path) + data = self.path.split('/',3) + data.append(0) + print("added : ",data[2],data[3],data[4]) + cur.execute("insert into location values(?,?,?)",data[2:5]) + con.commit() + self.end_headers() + + + +# we have just overrided the do get method of simplehttprequesthandler +# and now we are just making a handler out of modified simplehttprequesthandler +http = socketserver.TCPServer(("",port),myhandler) + +print("serving at port",port) +http.serve_forever() \ No newline at end of file diff --git a/backend/week1/tempCodeRunnerFile.py b/backend/week1/tempCodeRunnerFile.py new file mode 100644 index 000000000..06a576035 --- /dev/null +++ b/backend/week1/tempCodeRunnerFile.py @@ -0,0 +1 @@ +TE \ No newline at end of file diff --git a/backend/week1/~$report.md b/backend/week1/~$report.md new file mode 100644 index 000000000..98c5e9280 Binary files /dev/null and b/backend/week1/~$report.md differ diff --git a/backend/week2/Scripts/Activate.ps1 b/backend/week2/Scripts/Activate.ps1 new file mode 100644 index 000000000..d3c79649f --- /dev/null +++ b/backend/week2/Scripts/Activate.ps1 @@ -0,0 +1,472 @@ +<# +.Synopsis +Activate a Python virtual environment for the current PowerShell session. + +.Description +Pushes the python executable for a virtual environment to the front of the +$Env:PATH environment variable and sets the prompt to signify that you are +in a Python virtual environment. Makes use of the command line switches as +well as the `pyvenv.cfg` file values present in the virtual environment. + +.Parameter VenvDir +Path to the directory that contains the virtual environment to activate. The +default value for this is the parent of the directory that the Activate.ps1 +script is located within. + +.Parameter Prompt +The prompt prefix to display when this virtual environment is activated. By +default, this prompt is the name of the virtual environment folder (VenvDir) +surrounded by parentheses and followed by a single space (ie. '(.venv) '). + +.Example +Activate.ps1 +Activates the Python virtual environment that contains the Activate.ps1 script. + +.Example +Activate.ps1 -Verbose +Activates the Python virtual environment that contains the Activate.ps1 script, +and shows extra information about the activation as it executes. + +.Example +Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv +Activates the Python virtual environment located in the specified location. + +.Example +Activate.ps1 -Prompt "MyPython" +Activates the Python virtual environment that contains the Activate.ps1 script, +and prefixes the current prompt with the specified string (surrounded in +parentheses) while the virtual environment is active. + +.Notes +On Windows, it may be required to enable this Activate.ps1 script by setting the +execution policy for the user. You can do this by issuing the following PowerShell +command: + +PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + +For more information on Execution Policies: +https://go.microsoft.com/fwlink/?LinkID=135170 + +#> +Param( + [Parameter(Mandatory = $false)] + [String] + $VenvDir, + [Parameter(Mandatory = $false)] + [String] + $Prompt +) + +<# Function declarations --------------------------------------------------- #> + +<# +.Synopsis +Remove all shell session elements added by the Activate script, including the +addition of the virtual environment's Python executable from the beginning of +the PATH variable. + +.Parameter NonDestructive +If present, do not remove this function from the global namespace for the +session. + +#> +function global:deactivate ([switch]$NonDestructive) { + # Revert to original values + + # The prior prompt: + if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { + Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt + Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT + } + + # The prior PYTHONHOME: + if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { + Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME + Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME + } + + # The prior PATH: + if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { + Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH + Remove-Item -Path Env:_OLD_VIRTUAL_PATH + } + + # Just remove the VIRTUAL_ENV altogether: + if (Test-Path -Path Env:VIRTUAL_ENV) { + Remove-Item -Path env:VIRTUAL_ENV + } + + # Just remove VIRTUAL_ENV_PROMPT altogether. + if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) { + Remove-Item -Path env:VIRTUAL_ENV_PROMPT + } + + # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: + if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { + Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force + } + + # Leave deactivate function in the global namespace if requested: + if (-not $NonDestructive) { + Remove-Item -Path function:deactivate + } +} + +<# +.Description +Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the +given folder, and returns them in a map. + +For each line in the pyvenv.cfg file, if that line can be parsed into exactly +two strings separated by `=` (with any amount of whitespace surrounding the =) +then it is considered a `key = value` line. The left hand string is the key, +the right hand is the value. + +If the value starts with a `'` or a `"` then the first and last character is +stripped from the value before being captured. + +.Parameter ConfigDir +Path to the directory that contains the `pyvenv.cfg` file. +#> +function Get-PyVenvConfig( + [String] + $ConfigDir +) { + Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" + + # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). + $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue + + # An empty map will be returned if no config file is found. + $pyvenvConfig = @{ } + + if ($pyvenvConfigPath) { + + Write-Verbose "File exists, parse `key = value` lines" + $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath + + $pyvenvConfigContent | ForEach-Object { + $keyval = $PSItem -split "\s*=\s*", 2 + if ($keyval[0] -and $keyval[1]) { + $val = $keyval[1] + + # Remove extraneous quotations around a string value. + if ("'""".Contains($val.Substring(0, 1))) { + $val = $val.Substring(1, $val.Length - 2) + } + + $pyvenvConfig[$keyval[0]] = $val + Write-Verbose "Adding Key: '$($keyval[0])'='$val'" + } + } + } + return $pyvenvConfig +} + + +<# Begin Activate script --------------------------------------------------- #> + +# Determine the containing directory of this script +$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition +$VenvExecDir = Get-Item -Path $VenvExecPath + +Write-Verbose "Activation script is located in path: '$VenvExecPath'" +Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" +Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" + +# Set values required in priority: CmdLine, ConfigFile, Default +# First, get the location of the virtual environment, it might not be +# VenvExecDir if specified on the command line. +if ($VenvDir) { + Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" +} +else { + Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." + $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") + Write-Verbose "VenvDir=$VenvDir" +} + +# Next, read the `pyvenv.cfg` file to determine any required value such +# as `prompt`. +$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir + +# Next, set the prompt from the command line, or the config file, or +# just use the name of the virtual environment folder. +if ($Prompt) { + Write-Verbose "Prompt specified as argument, using '$Prompt'" +} +else { + Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" + if ($pyvenvCfg -and $pyvenvCfg['prompt']) { + Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" + $Prompt = $pyvenvCfg['prompt']; + } + else { + Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)" + Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" + $Prompt = Split-Path -Path $venvDir -Leaf + } +} + +Write-Verbose "Prompt = '$Prompt'" +Write-Verbose "VenvDir='$VenvDir'" + +# Deactivate any currently active virtual environment, but leave the +# deactivate function in place. +deactivate -nondestructive + +# Now set the environment variable VIRTUAL_ENV, used by many tools to determine +# that there is an activated venv. +$env:VIRTUAL_ENV = $VenvDir + +if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { + + Write-Verbose "Setting prompt to '$Prompt'" + + # Set the prompt to include the env name + # Make sure _OLD_VIRTUAL_PROMPT is global + function global:_OLD_VIRTUAL_PROMPT { "" } + Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT + New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt + + function global:prompt { + Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " + _OLD_VIRTUAL_PROMPT + } + $env:VIRTUAL_ENV_PROMPT = $Prompt +} + +# Clear PYTHONHOME +if (Test-Path -Path Env:PYTHONHOME) { + Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME + Remove-Item -Path Env:PYTHONHOME +} + +# Add the venv to the PATH +Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH +$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" + +# SIG # Begin signature block +# MIIpiQYJKoZIhvcNAQcCoIIpejCCKXYCAQExDzANBglghkgBZQMEAgEFADB5Bgor +# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG +# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBnL745ElCYk8vk +# dBtMuQhLeWJ3ZGfzKW4DHCYzAn+QB6CCDi8wggawMIIEmKADAgECAhAIrUCyYNKc +# TJ9ezam9k67ZMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK +# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV +# BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0z +# NjA0MjgyMzU5NTlaMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg +# SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcg +# UlNBNDA5NiBTSEEzODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +# ggIKAoICAQDVtC9C0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0 +# JAfhS0/TeEP0F9ce2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJr +# Q5qZ8sU7H/Lvy0daE6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhF +# LqGfLOEYwhrMxe6TSXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+F +# LEikVoQ11vkunKoAFdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh +# 3K3kGKDYwSNHR7OhD26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJ +# wZPt4bRc4G/rJvmM1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQay +# g9Rc9hUZTO1i4F4z8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbI +# YViY9XwCFjyDKK05huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchAp +# QfDVxW0mdmgRQRNYmtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRro +# OBl8ZhzNeDhFMJlP/2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IB +# WTCCAVUwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+ +# YXsIiGX0TkIwHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0P +# AQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAk +# BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAC +# hjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9v +# dEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5j +# b20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAED +# MAgGBmeBDAEEATANBgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql +# +Eg08yy25nRm95RysQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFF +# UP2cvbaF4HZ+N3HLIvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1h +# mYFW9snjdufE5BtfQ/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3Ryw +# YFzzDaju4ImhvTnhOE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5Ubdld +# AhQfQDN8A+KVssIhdXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw +# 8MzK7/0pNVwfiThV9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnP +# LqR0kq3bPKSchh/jwVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatE +# QOON8BUozu3xGFYHKi8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bn +# KD+sEq6lLyJsQfmCXBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQji +# WQ1tygVQK+pKHJ6l/aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbq +# yK+p/pQd52MbOoZWeE4wggd3MIIFX6ADAgECAhAHHxQbizANJfMU6yMM0NHdMA0G +# CSqGSIb3DQEBCwUAMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg +# SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcg +# UlNBNDA5NiBTSEEzODQgMjAyMSBDQTEwHhcNMjIwMTE3MDAwMDAwWhcNMjUwMTE1 +# MjM1OTU5WjB8MQswCQYDVQQGEwJVUzEPMA0GA1UECBMGT3JlZ29uMRIwEAYDVQQH +# EwlCZWF2ZXJ0b24xIzAhBgNVBAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9u +# MSMwIQYDVQQDExpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjCCAiIwDQYJKoZI +# hvcNAQEBBQADggIPADCCAgoCggIBAKgc0BTT+iKbtK6f2mr9pNMUTcAJxKdsuOiS +# YgDFfwhjQy89koM7uP+QV/gwx8MzEt3c9tLJvDccVWQ8H7mVsk/K+X+IufBLCgUi +# 0GGAZUegEAeRlSXxxhYScr818ma8EvGIZdiSOhqjYc4KnfgfIS4RLtZSrDFG2tN1 +# 6yS8skFa3IHyvWdbD9PvZ4iYNAS4pjYDRjT/9uzPZ4Pan+53xZIcDgjiTwOh8VGu +# ppxcia6a7xCyKoOAGjvCyQsj5223v1/Ig7Dp9mGI+nh1E3IwmyTIIuVHyK6Lqu35 +# 2diDY+iCMpk9ZanmSjmB+GMVs+H/gOiofjjtf6oz0ki3rb7sQ8fTnonIL9dyGTJ0 +# ZFYKeb6BLA66d2GALwxZhLe5WH4Np9HcyXHACkppsE6ynYjTOd7+jN1PRJahN1oE +# RzTzEiV6nCO1M3U1HbPTGyq52IMFSBM2/07WTJSbOeXjvYR7aUxK9/ZkJiacl2iZ +# I7IWe7JKhHohqKuceQNyOzxTakLcRkzynvIrk33R9YVqtB4L6wtFxhUjvDnQg16x +# ot2KVPdfyPAWd81wtZADmrUtsZ9qG79x1hBdyOl4vUtVPECuyhCxaw+faVjumapP +# Unwo8ygflJJ74J+BYxf6UuD7m8yzsfXWkdv52DjL74TxzuFTLHPyARWCSCAbzn3Z +# Ily+qIqDAgMBAAGjggIGMIICAjAfBgNVHSMEGDAWgBRoN+Drtjv4XxGG+/5hewiI +# ZfROQjAdBgNVHQ4EFgQUt/1Teh2XDuUj2WW3siYWJgkZHA8wDgYDVR0PAQH/BAQD +# AgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMIG1BgNVHR8Ega0wgaowU6BRoE+GTWh0 +# dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWdu +# aW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3JsMFOgUaBPhk1odHRwOi8vY3JsNC5k +# aWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZT +# SEEzODQyMDIxQ0ExLmNybDA+BgNVHSAENzA1MDMGBmeBDAEEATApMCcGCCsGAQUF +# BwIBFhtodHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgZQGCCsGAQUFBwEBBIGH +# MIGEMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wXAYIKwYB +# BQUHMAKGUGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0 +# ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3J0MAwGA1UdEwEB +# /wQCMAAwDQYJKoZIhvcNAQELBQADggIBABxv4AeV/5ltkELHSC63fXAFYS5tadcW +# TiNc2rskrNLrfH1Ns0vgSZFoQxYBFKI159E8oQQ1SKbTEubZ/B9kmHPhprHya08+ +# VVzxC88pOEvz68nA82oEM09584aILqYmj8Pj7h/kmZNzuEL7WiwFa/U1hX+XiWfL +# IJQsAHBla0i7QRF2de8/VSF0XXFa2kBQ6aiTsiLyKPNbaNtbcucaUdn6vVUS5izW +# OXM95BSkFSKdE45Oq3FForNJXjBvSCpwcP36WklaHL+aHu1upIhCTUkzTHMh8b86 +# WmjRUqbrnvdyR2ydI5l1OqcMBjkpPpIV6wcc+KY/RH2xvVuuoHjlUjwq2bHiNoX+ +# W1scCpnA8YTs2d50jDHUgwUo+ciwpffH0Riq132NFmrH3r67VaN3TuBxjI8SIZM5 +# 8WEDkbeoriDk3hxU8ZWV7b8AW6oyVBGfM06UgkfMb58h+tJPrFx8VI/WLq1dTqMf +# ZOm5cuclMnUHs2uqrRNtnV8UfidPBL4ZHkTcClQbCoz0UbLhkiDvIS00Dn+BBcxw +# /TKqVL4Oaz3bkMSsM46LciTeucHY9ExRVt3zy7i149sd+F4QozPqn7FrSVHXmem3 +# r7bjyHTxOgqxRCVa18Vtx7P/8bYSBeS+WHCKcliFCecspusCDSlnRUjZwyPdP0VH +# xaZg2unjHY3rMYIasDCCGqwCAQEwfTBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMO +# RGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgQ29k +# ZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExAhAHHxQbizANJfMU6yMM +# 0NHdMA0GCWCGSAFlAwQCAQUAoIHEMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEE +# MBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCBn +# AZ6P7YvTwq0fbF62o7E75R0LxsW5OtyYiFESQckLhjBYBgorBgEEAYI3AgEMMUow +# SKBGgEQAQgB1AGkAbAB0ADoAIABSAGUAbABlAGEAcwBlAF8AdgAzAC4AMQAxAC4A +# MQBfADIAMAAyADIAMQAyADAANgAuADAAMTANBgkqhkiG9w0BAQEFAASCAgCUdOps +# v3eE2jWZC7R7IKjKvAhB1gqrrqyEOYU6Cy/U9zWWGw8t+HD9dJSqPiUm0mPoRYp8 +# 7DNFKsAGUczwXyI144D50rnrn8qma2mhxw7FmrOcwu+Yw3VYoke9OHy/oiyRKd7s +# NifbuVOepKGHgz/36TTstpclCCd4CsT/nDp1DIZbDYLcJXeRm1dfTM64GRO8JVF5 +# IpYVLoDzzTmj3Jyh+9172T9l/1jymYmanKmXfjnbOTgtpyPZU1RXFYGi/LIl8KXK +# SgPjbN+cWjcTxEOagcKdaDGF6NL+zV0a7cCBkarnTpt9GP5nRXVMFLsphn+9e9R0 +# Rj7z62LPu1U2s9lwCAVFtnECE/5rLu8yGIKKAHNbyb6iX/4EJKeoUc47oXHgJmvB +# 5Ch6oSjTKjSU/bOFDTEO0qIeR7wn7oONu3rjM+2ftVw4hsI1a2+Q0CPP+jMxTAV+ +# Iw1UzNFwbNf6lELnoK0zVSYwcd4pTi1F7/ZRfuo4u+hExkMEY3kz4+7RbeZIuJnJ +# x6WfiyPLOmIqXSm+y9qkBm+TLRVBW4/6ccIeGpSPvsse27YioQ5eZleXJnG4KfpR +# LRRvsq6rhR3a07P0/ZT8H3sP0TY1xOB7KdzTOENXrcAz77t0qYvJhABeKdUAzOyQ +# G3WD2r9CJvyuL8CLYp/xdIqW1yPEOogYW2YE5KGCFz0wghc5BgorBgEEAYI3AwMB +# MYIXKTCCFyUGCSqGSIb3DQEHAqCCFxYwghcSAgEDMQ8wDQYJYIZIAWUDBAIBBQAw +# dwYLKoZIhvcNAQkQAQSgaARmMGQCAQEGCWCGSAGG/WwHATAxMA0GCWCGSAFlAwQC +# AQUABCDl0KR5xtUwOHsKmWo2svZfpRLlEzNgxZDMnLShuhGYmAIQbnZ9CIcvuYaF +# E9nJOOmu7hgPMjAyMjEyMDYyMDA2MjdaoIITBzCCBsAwggSooAMCAQICEAxNaXJL +# lPo8Kko9KQeAPVowDQYJKoZIhvcNAQELBQAwYzELMAkGA1UEBhMCVVMxFzAVBgNV +# BAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0 +# IFJTQTQwOTYgU0hBMjU2IFRpbWVTdGFtcGluZyBDQTAeFw0yMjA5MjEwMDAwMDBa +# Fw0zMzExMjEyMzU5NTlaMEYxCzAJBgNVBAYTAlVTMREwDwYDVQQKEwhEaWdpQ2Vy +# dDEkMCIGA1UEAxMbRGlnaUNlcnQgVGltZXN0YW1wIDIwMjIgLSAyMIICIjANBgkq +# hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAz+ylJjrGqfJru43BDZrboegUhXQzGias +# 0BxVHh42bbySVQxh9J0Jdz0Vlggva2Sk/QaDFteRkjgcMQKW+3KxlzpVrzPsYYrp +# pijbkGNcvYlT4DotjIdCriak5Lt4eLl6FuFWxsC6ZFO7KhbnUEi7iGkMiMbxvuAv +# fTuxylONQIMe58tySSgeTIAehVbnhe3yYbyqOgd99qtu5Wbd4lz1L+2N1E2VhGjj +# gMtqedHSEJFGKes+JvK0jM1MuWbIu6pQOA3ljJRdGVq/9XtAbm8WqJqclUeGhXk+ +# DF5mjBoKJL6cqtKctvdPbnjEKD+jHA9QBje6CNk1prUe2nhYHTno+EyREJZ+TeHd +# wq2lfvgtGx/sK0YYoxn2Off1wU9xLokDEaJLu5i/+k/kezbvBkTkVf826uV8Mefz +# wlLE5hZ7Wn6lJXPbwGqZIS1j5Vn1TS+QHye30qsU5Thmh1EIa/tTQznQZPpWz+D0 +# CuYUbWR4u5j9lMNzIfMvwi4g14Gs0/EH1OG92V1LbjGUKYvmQaRllMBY5eUuKZCm +# t2Fk+tkgbBhRYLqmgQ8JJVPxvzvpqwcOagc5YhnJ1oV/E9mNec9ixezhe7nMZxMH +# msF47caIyLBuMnnHC1mDjcbu9Sx8e47LZInxscS451NeX1XSfRkpWQNO+l3qRXMc +# hH7XzuLUOncCAwEAAaOCAYswggGHMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8E +# AjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMCAGA1UdIAQZMBcwCAYGZ4EMAQQC +# MAsGCWCGSAGG/WwHATAfBgNVHSMEGDAWgBS6FtltTYUvcyl2mi91jGogj57IbzAd +# BgNVHQ4EFgQUYore0GH8jzEU7ZcLzT0qlBTfUpwwWgYDVR0fBFMwUTBPoE2gS4ZJ +# aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5 +# NlNIQTI1NlRpbWVTdGFtcGluZ0NBLmNybDCBkAYIKwYBBQUHAQEEgYMwgYAwJAYI +# KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBYBggrBgEFBQcwAoZM +# aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNB +# NDA5NlNIQTI1NlRpbWVTdGFtcGluZ0NBLmNydDANBgkqhkiG9w0BAQsFAAOCAgEA +# VaoqGvNG83hXNzD8deNP1oUj8fz5lTmbJeb3coqYw3fUZPwV+zbCSVEseIhjVQlG +# OQD8adTKmyn7oz/AyQCbEx2wmIncePLNfIXNU52vYuJhZqMUKkWHSphCK1D8G7We +# CDAJ+uQt1wmJefkJ5ojOfRu4aqKbwVNgCeijuJ3XrR8cuOyYQfD2DoD75P/fnRCn +# 6wC6X0qPGjpStOq/CUkVNTZZmg9U0rIbf35eCa12VIp0bcrSBWcrduv/mLImlTgZ +# iEQU5QpZomvnIj5EIdI/HMCb7XxIstiSDJFPPGaUr10CU+ue4p7k0x+GAWScAMLp +# WnR1DT3heYi/HAGXyRkjgNc2Wl+WFrFjDMZGQDvOXTXUWT5Dmhiuw8nLw/ubE19q +# tcfg8wXDWd8nYiveQclTuf80EGf2JjKYe/5cQpSBlIKdrAqLxksVStOYkEVgM4Dg +# I974A6T2RUflzrgDQkfoQTZxd639ouiXdE4u2h4djFrIHprVwvDGIqhPm73YHJpR +# xC+a9l+nJ5e6li6FV8Bg53hWf2rvwpWaSxECyIKcyRoFfLpxtU56mWz06J7UWpjI +# n7+NuxhcQ/XQKujiYu54BNu90ftbCqhwfvCXhHjjCANdRyxjqCU4lwHSPzra5eX2 +# 5pvcfizM/xdMTQCi2NYBDriL7ubgclWJLCcZYfZ3AYwwggauMIIElqADAgECAhAH +# Nje3JFR82Ees/ShmKl5bMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUw +# EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +# ITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yMjAzMjMwMDAw +# MDBaFw0zNzAzMjIyMzU5NTlaMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdp +# Q2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2 +# IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +# ggIKAoICAQDGhjUGSbPBPXJJUVXHJQPE8pE3qZdRodbSg9GeTKJtoLDMg/la9hGh +# RBVCX6SI82j6ffOciQt/nR+eDzMfUBMLJnOWbfhXqAJ9/UO0hNoR8XOxs+4rgISK +# Ihjf69o9xBd/qxkrPkLcZ47qUT3w1lbU5ygt69OxtXXnHwZljZQp09nsad/ZkIdG +# AHvbREGJ3HxqV3rwN3mfXazL6IRktFLydkf3YYMZ3V+0VAshaG43IbtArF+y3kp9 +# zvU5EmfvDqVjbOSmxR3NNg1c1eYbqMFkdECnwHLFuk4fsbVYTXn+149zk6wsOeKl +# SNbwsDETqVcplicu9Yemj052FVUmcJgmf6AaRyBD40NjgHt1biclkJg6OBGz9vae +# 5jtb7IHeIhTZgirHkr+g3uM+onP65x9abJTyUpURK1h0QCirc0PO30qhHGs4xSnz +# yqqWc0Jon7ZGs506o9UD4L/wojzKQtwYSH8UNM/STKvvmz3+DrhkKvp1KCRB7UK/ +# BZxmSVJQ9FHzNklNiyDSLFc1eSuo80VgvCONWPfcYd6T/jnA+bIwpUzX6ZhKWD7T +# A4j+s4/TXkt2ElGTyYwMO1uKIqjBJgj5FBASA31fI7tk42PgpuE+9sJ0sj8eCXbs +# q11GdeJgo1gJASgADoRU7s7pXcheMBK9Rp6103a50g5rmQzSM7TNsQIDAQABo4IB +# XTCCAVkwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUuhbZbU2FL3Mpdpov +# dYxqII+eyG8wHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0P +# AQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAk +# BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAC +# hjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9v +# dEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5j +# b20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEE +# AjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIBAH1ZjsCTtm+YqUQiAX5m +# 1tghQuGwGC4QTRPPMFPOvxj7x1Bd4ksp+3CKDaopafxpwc8dB+k+YMjYC+VcW9dt +# h/qEICU0MWfNthKWb8RQTGIdDAiCqBa9qVbPFXONASIlzpVpP0d3+3J0FNf/q0+K +# LHqrhc1DX+1gtqpPkWaeLJ7giqzl/Yy8ZCaHbJK9nXzQcAp876i8dU+6WvepELJd +# 6f8oVInw1YpxdmXazPByoyP6wCeCRK6ZJxurJB4mwbfeKuv2nrF5mYGjVoarCkXJ +# 38SNoOeY+/umnXKvxMfBwWpx2cYTgAnEtp/Nh4cku0+jSbl3ZpHxcpzpSwJSpzd+ +# k1OsOx0ISQ+UzTl63f8lY5knLD0/a6fxZsNBzU+2QJshIUDQtxMkzdwdeDrknq3l +# NHGS1yZr5Dhzq6YBT70/O3itTK37xJV77QpfMzmHQXh6OOmc4d0j/R0o08f56PGY +# X/sr2H7yRp11LB4nLCbbbxV7HhmLNriT1ObyF5lZynDwN7+YAN8gFk8n+2BnFqFm +# ut1VwDophrCYoCvtlUG3OtUVmDG0YgkPCr2B2RP+v6TR81fZvAT6gt4y3wSJ8ADN +# XcL50CN/AAvkdgIm2fBldkKmKYcJRyvmfxqkhQ/8mJb2VVQrH4D6wPIOK+XW+6kv +# RBVK5xMOHds3OBqhK/bt1nz8MIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAY +# WjANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNl +# cnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdp +# Q2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcNMzExMTA5 +# MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkw +# FwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVz +# dGVkIFJvb3QgRzQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBz +# aN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbr +# VsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTR +# EEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJ +# z82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyO +# j4DatpGYQJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6R +# AXwhTNS8rhsDdV14Ztk6MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k +# 98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJ +# tppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUa +# dmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZB +# dd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVf +# nSD8oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo4IBOjCCATYwDwYDVR0T +# AQH/BAUwAwEB/zAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wHwYDVR0j +# BBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDgYDVR0PAQH/BAQDAgGGMHkGCCsG +# AQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t +# MEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl +# cnRBc3N1cmVkSURSb290Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9j +# cmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwEQYD +# VR0gBAowCDAGBgRVHSAAMA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXnOF+go3Qb +# PbYW1/e/Vwe9mqyhhyzshV6pGrsi+IcaaVQi7aSId229GhT0E0p6Ly23OO/0/4C5 +# +KH38nLeJLxSA8hO0Cre+i1Wz/n096wwepqLsl7Uz9FDRJtDIeuWcqFItJnLnU+n +# BgMTdydE1Od/6Fmo8L8vC6bp8jQ87PcDx4eo0kxAGTVGamlUsLihVo7spNU96LHc +# /RzY9HdaXFSMb++hUD38dglohJ9vytsgjTVgHAIDyyCwrFigDkBjxZgiwbJZ9VVr +# zyerbHbObyMt9H5xaiNrIv8SuFQtJ37YOtnwtoeW/VvRXKwYw02fc7cBqZ9Xql4o +# 4rmUMYIDdjCCA3ICAQEwdzBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNl +# cnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBT +# SEEyNTYgVGltZVN0YW1waW5nIENBAhAMTWlyS5T6PCpKPSkHgD1aMA0GCWCGSAFl +# AwQCAQUAoIHRMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0B +# CQUxDxcNMjIxMjA2MjAwNjI3WjArBgsqhkiG9w0BCRACDDEcMBowGDAWBBTzhyJN +# hjOCkjWplLy9j5bp/hx8czAvBgkqhkiG9w0BCQQxIgQgjZC+rPrPBAlmFuP+OmvD +# yh8xqQf/ReQsUWtJ8pZa3hUwNwYLKoZIhvcNAQkQAi8xKDAmMCQwIgQgx/ThvjIo +# iSCr4iY6vhrE/E/meBwtZNBMgHVXoCO1tvowDQYJKoZIhvcNAQEBBQAEggIAAgln +# xfP1/ZMQMCTCCrVb3qm7DI8RVNeUM4QEZuxpKvqe9reisD1nem6Z1zKW+5oP7NxF +# /0u8JCTKwkpMZv8m/qcp7TQ3vwHbRqRpNNw/CFd/H0OrLnD14r3jhnNoS/XU0jZi +# U/f9vNl/4qStFMu30yKuxlsycj/At2/ohTZBSWPdv9e+XL3mLZ8HMmwRR5o9Kldg +# p/ErSHOYSqaQLx5/eBF59qtIKsw1WAQITvCW7zTII/gEuCz+myl+7aBAaPrW0mUa +# FVrWQL/Ug3PcwNB7ZK+py7q9eXmQShskSaWXYnl8qCJj4Yex6/D3BMZnDIGXamia +# sH41UoqaeJaqcPvErMyvnCC928552hFjpmEz3PFyVdS04KfjE71CmzDiSNy/jWMM +# W748v6ZnqIGUkYev8D0D4aiZBoYzi4uHuVS7NPCbTakIIbxXeT9Jw1L4xVe6tN+l +# ucDC5UVeuZ8dB2OU+oX0sjTvFRG8V1O2OBBLyNKHtCkFXgpkgFH1Ff/c/XCFgLFV +# ymSCD/LY0EBtJvNUe7EBGM7TWwSVfDNEqz2rAvMERz6F4GRq6MJ5aVfPZ6mx/7qj +# Qs3ScAftPwKYlGJWYmewG+AvHjaHB4Yv1q/19tMjTIiQ4YLk0GaHd6BanFmwpe0f +# Abhwpg6wH7UGifzI6/6kgrdXF80c98cDuAxVg2w= +# SIG # End signature block diff --git a/backend/week2/Scripts/activate b/backend/week2/Scripts/activate new file mode 100644 index 000000000..bb06b290d --- /dev/null +++ b/backend/week2/Scripts/activate @@ -0,0 +1,69 @@ +# This file must be used with "source bin/activate" *from bash* +# you cannot run it directly + +deactivate () { + # reset old environment variables + if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then + PATH="${_OLD_VIRTUAL_PATH:-}" + export PATH + unset _OLD_VIRTUAL_PATH + fi + if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then + PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}" + export PYTHONHOME + unset _OLD_VIRTUAL_PYTHONHOME + fi + + # This should detect bash and zsh, which have a hash command that must + # be called to get it to forget past commands. Without forgetting + # past commands the $PATH changes we made may not be respected + if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then + hash -r 2> /dev/null + fi + + if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then + PS1="${_OLD_VIRTUAL_PS1:-}" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + unset VIRTUAL_ENV + unset VIRTUAL_ENV_PROMPT + if [ ! "${1:-}" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelevant variables +deactivate nondestructive + +VIRTUAL_ENV="C:\src\projectlocationtwo\dsocbackend\backend" +export VIRTUAL_ENV + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/Scripts:$PATH" +export PATH + +# unset PYTHONHOME if set +# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) +# could use `if (set -u; : $PYTHONHOME) ;` in bash +if [ -n "${PYTHONHOME:-}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then + _OLD_VIRTUAL_PS1="${PS1:-}" + PS1="(backend) ${PS1:-}" + export PS1 + VIRTUAL_ENV_PROMPT="(backend) " + export VIRTUAL_ENV_PROMPT +fi + +# This should detect bash and zsh, which have a hash command that must +# be called to get it to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then + hash -r 2> /dev/null +fi diff --git a/backend/week2/Scripts/activate.bat b/backend/week2/Scripts/activate.bat new file mode 100644 index 000000000..4b45a4435 --- /dev/null +++ b/backend/week2/Scripts/activate.bat @@ -0,0 +1,34 @@ +@echo off + +rem This file is UTF-8 encoded, so we need to update the current code page while executing it +for /f "tokens=2 delims=:." %%a in ('"%SystemRoot%\System32\chcp.com"') do ( + set _OLD_CODEPAGE=%%a +) +if defined _OLD_CODEPAGE ( + "%SystemRoot%\System32\chcp.com" 65001 > nul +) + +set VIRTUAL_ENV=C:\src\projectlocationtwo\dsocbackend\backend + +if not defined PROMPT set PROMPT=$P$G + +if defined _OLD_VIRTUAL_PROMPT set PROMPT=%_OLD_VIRTUAL_PROMPT% +if defined _OLD_VIRTUAL_PYTHONHOME set PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME% + +set _OLD_VIRTUAL_PROMPT=%PROMPT% +set PROMPT=(backend) %PROMPT% + +if defined PYTHONHOME set _OLD_VIRTUAL_PYTHONHOME=%PYTHONHOME% +set PYTHONHOME= + +if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH% +if not defined _OLD_VIRTUAL_PATH set _OLD_VIRTUAL_PATH=%PATH% + +set PATH=%VIRTUAL_ENV%\Scripts;%PATH% +set VIRTUAL_ENV_PROMPT=(backend) + +:END +if defined _OLD_CODEPAGE ( + "%SystemRoot%\System32\chcp.com" %_OLD_CODEPAGE% > nul + set _OLD_CODEPAGE= +) diff --git a/backend/week2/Scripts/deactivate.bat b/backend/week2/Scripts/deactivate.bat new file mode 100644 index 000000000..62a39a758 --- /dev/null +++ b/backend/week2/Scripts/deactivate.bat @@ -0,0 +1,22 @@ +@echo off + +if defined _OLD_VIRTUAL_PROMPT ( + set "PROMPT=%_OLD_VIRTUAL_PROMPT%" +) +set _OLD_VIRTUAL_PROMPT= + +if defined _OLD_VIRTUAL_PYTHONHOME ( + set "PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME%" + set _OLD_VIRTUAL_PYTHONHOME= +) + +if defined _OLD_VIRTUAL_PATH ( + set "PATH=%_OLD_VIRTUAL_PATH%" +) + +set _OLD_VIRTUAL_PATH= + +set VIRTUAL_ENV= +set VIRTUAL_ENV_PROMPT= + +:END diff --git a/backend/week2/Scripts/django-admin.exe b/backend/week2/Scripts/django-admin.exe new file mode 100644 index 000000000..0646e39cd Binary files /dev/null and b/backend/week2/Scripts/django-admin.exe differ diff --git a/backend/week2/Scripts/pip.exe b/backend/week2/Scripts/pip.exe new file mode 100644 index 000000000..6c87e93b3 Binary files /dev/null and b/backend/week2/Scripts/pip.exe differ diff --git a/backend/week2/Scripts/pip3.11.exe b/backend/week2/Scripts/pip3.11.exe new file mode 100644 index 000000000..6c87e93b3 Binary files /dev/null and b/backend/week2/Scripts/pip3.11.exe differ diff --git a/backend/week2/Scripts/pip3.exe b/backend/week2/Scripts/pip3.exe new file mode 100644 index 000000000..6c87e93b3 Binary files /dev/null and b/backend/week2/Scripts/pip3.exe differ diff --git a/backend/week2/Scripts/python.exe b/backend/week2/Scripts/python.exe new file mode 100644 index 000000000..4b0ea800c Binary files /dev/null and b/backend/week2/Scripts/python.exe differ diff --git a/backend/week2/Scripts/pythonw.exe b/backend/week2/Scripts/pythonw.exe new file mode 100644 index 000000000..656e19853 Binary files /dev/null and b/backend/week2/Scripts/pythonw.exe differ diff --git a/backend/week2/Scripts/sqlformat.exe b/backend/week2/Scripts/sqlformat.exe new file mode 100644 index 000000000..56494be1e Binary files /dev/null and b/backend/week2/Scripts/sqlformat.exe differ diff --git a/backend/week2/mydjangoproject/ecommerce/__init__.py b/backend/week2/mydjangoproject/ecommerce/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/week2/mydjangoproject/ecommerce/admin.py b/backend/week2/mydjangoproject/ecommerce/admin.py new file mode 100644 index 000000000..0ffaa01bc --- /dev/null +++ b/backend/week2/mydjangoproject/ecommerce/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin + +# Register your models here. +from .models import product +admin.site.register(product) diff --git a/backend/week2/mydjangoproject/ecommerce/apps.py b/backend/week2/mydjangoproject/ecommerce/apps.py new file mode 100644 index 000000000..9a0a30839 --- /dev/null +++ b/backend/week2/mydjangoproject/ecommerce/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class EcommerceConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'ecommerce' diff --git a/backend/week2/mydjangoproject/ecommerce/forms.py b/backend/week2/mydjangoproject/ecommerce/forms.py new file mode 100644 index 000000000..878000c85 --- /dev/null +++ b/backend/week2/mydjangoproject/ecommerce/forms.py @@ -0,0 +1,8 @@ +from django import forms +from .models import product + +class mymodelform(forms.ModelForm): + class Meta: + model = product + fields = ["productIndex", "productName","productPrice","productDescription"] + labels = {"productIndex":"productIndex", "productName":"productName","productPrice":"productPrice","productDescription":"productDescription"} \ No newline at end of file diff --git a/backend/week2/mydjangoproject/ecommerce/migrations/0001_initial.py b/backend/week2/mydjangoproject/ecommerce/migrations/0001_initial.py new file mode 100644 index 000000000..10c24dfc8 --- /dev/null +++ b/backend/week2/mydjangoproject/ecommerce/migrations/0001_initial.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.3 on 2023-07-10 11:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='product', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('productIndex', models.IntegerField(default=0)), + ('productName', models.CharField(max_length=200)), + ('productPrice', models.IntegerField(default=0)), + ('productDescription', models.CharField(max_length=200)), + ], + ), + ] diff --git a/backend/week2/mydjangoproject/ecommerce/migrations/__init__.py b/backend/week2/mydjangoproject/ecommerce/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/week2/mydjangoproject/ecommerce/models.py b/backend/week2/mydjangoproject/ecommerce/models.py new file mode 100644 index 000000000..1714b2a3a --- /dev/null +++ b/backend/week2/mydjangoproject/ecommerce/models.py @@ -0,0 +1,10 @@ +from django.db import models + +# Create your models here. +class product(models.Model): + productIndex = models.IntegerField(default=0) + productName = models.CharField(max_length=200) + productPrice = models.IntegerField(default=0) + productDescription = models.CharField(max_length=200) + def __str__(self): + return self.productName \ No newline at end of file diff --git a/backend/week2/mydjangoproject/ecommerce/templates/ecommerce/addproducts.html b/backend/week2/mydjangoproject/ecommerce/templates/ecommerce/addproducts.html new file mode 100644 index 000000000..a554c95a3 --- /dev/null +++ b/backend/week2/mydjangoproject/ecommerce/templates/ecommerce/addproducts.html @@ -0,0 +1,10 @@ +
+
+
+ Form + {% csrf_token %} + {{ form.as_p }} + +
+
+
\ No newline at end of file diff --git a/backend/week2/mydjangoproject/ecommerce/templates/ecommerce/detail.html b/backend/week2/mydjangoproject/ecommerce/templates/ecommerce/detail.html new file mode 100644 index 000000000..042603dc6 --- /dev/null +++ b/backend/week2/mydjangoproject/ecommerce/templates/ecommerce/detail.html @@ -0,0 +1,6 @@ +

{{ product.productName }}

+
    +{% for choice in product.choice_set.all %} +
  • {{ choice.choice_text }}
  • +{% endfor %} +
\ No newline at end of file diff --git a/backend/week2/mydjangoproject/ecommerce/templates/ecommerce/index.html b/backend/week2/mydjangoproject/ecommerce/templates/ecommerce/index.html new file mode 100644 index 000000000..d98ecc6ec --- /dev/null +++ b/backend/week2/mydjangoproject/ecommerce/templates/ecommerce/index.html @@ -0,0 +1,23 @@ +{% if latest_product_list %} + +{% else %} +

No polls are available.

+{% endif %} +{% block title %}Home{% endblock %} + +{% block content %} +{% if user.is_authenticated %} + Hi {{ user.username }}! +

Log Out

+

Add your products

+{% else %} +

You are not logged in

+ Log In +

Please login to add your products.

+{% endif %} + +{% endblock %} \ No newline at end of file diff --git a/backend/week2/mydjangoproject/ecommerce/templates/ecommerce/register.html b/backend/week2/mydjangoproject/ecommerce/templates/ecommerce/register.html new file mode 100644 index 000000000..8f125845c --- /dev/null +++ b/backend/week2/mydjangoproject/ecommerce/templates/ecommerce/register.html @@ -0,0 +1,20 @@ +
+ {%if messages%} +
    + {%for message in messages%} +
  • {{message}}
  • + {%endfor%} +
+ {%endif%} +

Register to ecommerce

+
+ {% csrf_token %} + + {{ form.as_table }} + + + + +
+
+
\ No newline at end of file diff --git a/backend/week2/mydjangoproject/ecommerce/templates/registration/login.html b/backend/week2/mydjangoproject/ecommerce/templates/registration/login.html new file mode 100644 index 000000000..08e44a97c --- /dev/null +++ b/backend/week2/mydjangoproject/ecommerce/templates/registration/login.html @@ -0,0 +1,6 @@ +

Log In

+
+ {% csrf_token %} + {{ form.as_p }} + +
\ No newline at end of file diff --git a/backend/week2/mydjangoproject/ecommerce/templates/some b/backend/week2/mydjangoproject/ecommerce/templates/some new file mode 100644 index 000000000..e69de29bb diff --git a/backend/week2/mydjangoproject/ecommerce/tests.py b/backend/week2/mydjangoproject/ecommerce/tests.py new file mode 100644 index 000000000..7ce503c2d --- /dev/null +++ b/backend/week2/mydjangoproject/ecommerce/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/backend/week2/mydjangoproject/ecommerce/urls.py b/backend/week2/mydjangoproject/ecommerce/urls.py new file mode 100644 index 000000000..1a7a1af6c --- /dev/null +++ b/backend/week2/mydjangoproject/ecommerce/urls.py @@ -0,0 +1,11 @@ +from django.urls import path + +from . import views + +urlpatterns = [ + path("", views.index, name="index"), + path("/", views.productDetailView, name="productDetailView"), + path("list/",views.productlistView, name = "productlistview"), + path("register/",views.registerView,name = "registerView"), + path("addproducts/",views.createProductView,name = "createProductView"), +] \ No newline at end of file diff --git a/backend/week2/mydjangoproject/ecommerce/views.py b/backend/week2/mydjangoproject/ecommerce/views.py new file mode 100644 index 000000000..4b9fee22b --- /dev/null +++ b/backend/week2/mydjangoproject/ecommerce/views.py @@ -0,0 +1,63 @@ +from django.shortcuts import render,redirect +from django.contrib import messages +from django.contrib.auth.forms import UserCreationForm +from django.contrib.auth import login,authenticate +from django.http import Http404 +from django.http import HttpResponse +from django.template import loader +from .models import product +from .forms import mymodelform +from django.contrib.auth.decorators import login_required + +def index(request): + latest_product_list = product.objects.all() + template = loader.get_template("ecommerce/index.html") + context = { + "latest_product_list": latest_product_list, + } + return HttpResponse(template.render(context, request)) + +def productDetailView(request, product_id): + try: + item = product.objects.get(pk = product_id) + except: + raise Http404("Product does not exist.") + return render(request, "ecommerce/detail.html",{"product":item}) + +def productlistView(request): + return HttpResponse("You're at product list view.") + +def registerView(request): + if request.method == 'POST': + form = UserCreationForm(request.POST) + if form.is_valid(): + # username = form.cleaned_data.get('username') + # rawpassword = form.cleaned_data.get('password1') + # user = authenticate(username=username, password=rawpassword) + # login(request, user) + form.save() + print("registered") + return redirect('/ecommerce/') + else: + print("cannot register") + + else: + form = UserCreationForm() + print("ye kya hua") + context = {'form':form} + return render(request,'ecommerce/register.html',context) + +@login_required +def createProductView(request): + if request.method == "POST": + form = mymodelform(request.POST) + if form.is_valid: + form.save() + messages.success("created product successfully!!") + return redirect("ecommerce/addproducts.html") + else : + form = mymodelform() + return render(request,"ecommerce/addproducts.html",{'form':form}) + + +# Create your views here. diff --git a/backend/week2/mydjangoproject/manage.py b/backend/week2/mydjangoproject/manage.py new file mode 100644 index 000000000..62f3e6225 --- /dev/null +++ b/backend/week2/mydjangoproject/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mydjangoproject.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/backend/week2/mydjangoproject/mydjangoproject/__init__.py b/backend/week2/mydjangoproject/mydjangoproject/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/week2/mydjangoproject/mydjangoproject/asgi.py b/backend/week2/mydjangoproject/mydjangoproject/asgi.py new file mode 100644 index 000000000..7e23598f6 --- /dev/null +++ b/backend/week2/mydjangoproject/mydjangoproject/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for mydjangoproject project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mydjangoproject.settings') + +application = get_asgi_application() diff --git a/backend/week2/mydjangoproject/mydjangoproject/settings.py b/backend/week2/mydjangoproject/mydjangoproject/settings.py new file mode 100644 index 000000000..46fb493c4 --- /dev/null +++ b/backend/week2/mydjangoproject/mydjangoproject/settings.py @@ -0,0 +1,117 @@ +""" +Django settings for mydjangoproject project. + +Generated by 'django-admin startproject' using Django 4.2.3. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/4.2/ref/settings/ +""" + +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-1n-l#^()x)p(&k&g-u&o!g-qzohk*a6(25n@q^*f-l+=$yk8jp' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'ecommerce.apps.EcommerceConfig', + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'mydjangoproject.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [BASE_DIR/"templates"], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'mydjangoproject.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.2/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'Asia/Kolkata' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.2/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +LOGIN_REDIRECT_URL = "/ecommerce/" +LOGOUT_REDIRECT_URL = "/ecommerce/" diff --git a/backend/week2/mydjangoproject/mydjangoproject/urls.py b/backend/week2/mydjangoproject/mydjangoproject/urls.py new file mode 100644 index 000000000..f25d4a83e --- /dev/null +++ b/backend/week2/mydjangoproject/mydjangoproject/urls.py @@ -0,0 +1,24 @@ +""" +URL configuration for mydjangoproject project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/4.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path,include + +urlpatterns = [ + path("ecommerce/", include("ecommerce.urls")), + path("accounts/", include("django.contrib.auth.urls")), + path('admin/', admin.site.urls), +] diff --git a/backend/week2/mydjangoproject/mydjangoproject/wsgi.py b/backend/week2/mydjangoproject/mydjangoproject/wsgi.py new file mode 100644 index 000000000..f2f677db2 --- /dev/null +++ b/backend/week2/mydjangoproject/mydjangoproject/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for mydjangoproject project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mydjangoproject.settings') + +application = get_wsgi_application() diff --git a/backend/week2/pyvenv.cfg b/backend/week2/pyvenv.cfg new file mode 100644 index 000000000..14bcffe03 --- /dev/null +++ b/backend/week2/pyvenv.cfg @@ -0,0 +1,5 @@ +home = C:\Users\Dinu Goyal\AppData\Local\Programs\Python\Python311 +include-system-site-packages = false +version = 3.11.1 +executable = C:\Users\Dinu Goyal\AppData\Local\Programs\Python\Python311\python.exe +command = C:\Users\Dinu Goyal\AppData\Local\Programs\Python\Python311\python.exe -m venv C:\src\projectlocationtwo\dsocbackend\backend diff --git a/backend/week3/.vscode/settings.json b/backend/week3/.vscode/settings.json new file mode 100644 index 000000000..9ee86e71a --- /dev/null +++ b/backend/week3/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "[python]": { + "editor.defaultFormatter": "ms-python.autopep8" + }, + "python.formatting.provider": "none" +} \ No newline at end of file diff --git a/backend/week3/DEVClubSOC.postman_collection.json b/backend/week3/DEVClubSOC.postman_collection.json new file mode 100644 index 000000000..3ae8733fa --- /dev/null +++ b/backend/week3/DEVClubSOC.postman_collection.json @@ -0,0 +1,256 @@ +{ + "info": { + "_postman_id": "f558d601-5416-46b0-ba2f-938f3648f086", + "name": "DEVClubSOC", + "description": "This Collection of APIs is meant to be used for the website : [http://uniquedex100.iitd.site/ecommerce/]() and contain a collection of 7 APIs which can be easily used to access, create, delete and modify the products listed on above website.", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "28505962" + }, + "item": [ + { + "name": "Get All Products", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://uniquedex100.iitd.site/ecommerce/getallproducts/", + "protocol": "http", + "host": [ + "uniquedex100", + "iitd", + "site" + ], + "path": [ + "ecommerce", + "getallproducts", + "" + ] + }, + "description": "# _**Get All Products**_\n\nThis api can be used to fetch details of all the products available on the website and provide them in form of JSON text. Just send a request to the given link and it will return the desired values." + }, + "response": [] + }, + { + "name": "Get a Single Product (By ID)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://uniquedex100.iitd.site/ecommerce/getasingleproduct/3/", + "protocol": "http", + "host": [ + "uniquedex100", + "iitd", + "site" + ], + "path": [ + "ecommerce", + "getasingleproduct", + "3", + "" + ] + }, + "description": "# _**Get a Single Product (By ID)**_\n\nThis API can be used to get any product available on the marketplace by simply passing an ID along with the request. Send a get request to the given link along with a valid index and it will return the product details." + }, + "response": [] + }, + { + "name": "Add a Product", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjkwNjE0NDczLCJpYXQiOjE2OTA2MTQxNzMsImp0aSI6IjBiZjU2OTI1MzgyNzQ0MzliZTdhYTAyOGQ2NmE2YWY2IiwidXNlcl9pZCI6MX0.6GQvv6t8_QgbAjuTUhicCayw5NMZoInx1CzLU8pTYjw", + "type": "string" + } + ] + }, + "method": "PUT", + "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "productIndex", + "value": "33", + "type": "text" + }, + { + "key": "productName", + "value": "Dettol", + "type": "text" + }, + { + "key": "productPrice", + "value": "350", + "type": "text" + }, + { + "key": "productDescription", + "value": "Large bottle of dettol", + "type": "text" + } + ] + }, + "url": { + "raw": "http://uniquedex100.iitd.site/ecommerce/addaproduct/", + "protocol": "http", + "host": [ + "uniquedex100", + "iitd", + "site" + ], + "path": [ + "ecommerce", + "addaproduct", + "" + ] + }, + "description": "# _**Add a Product**_\n\nThis API can be used to add a product to the marketplace after successfully logging in. First generate a Bearer access token by going to link `/ecommerce/api/token` or by using the **API for login** and then paste it in the token section of authorization header after selecting bearer token. Then add the details of product in the Body as form data in form of JSON. Details may include `productIndex`, `productName`, `productPrice` and `productDescription`. Then send the `PUT` request." + }, + "response": [] + }, + { + "name": "Delete a Product", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjkwNjE0NzkxLCJpYXQiOjE2OTA2MTQ0OTEsImp0aSI6Ijg5ZDhhODA1ZjE1MzQ0ZTNhMjAyMGQ3Y2U2MmUwOTMwIiwidXNlcl9pZCI6MX0.PPW-LwOVuGYbFVGotI3GKZdpJgvuE81jlCJD2fabfXU", + "type": "string" + } + ] + }, + "method": "DELETE", + "header": [], + "url": { + "raw": "http://uniquedex100.iitd.site/ecommerce/deleteaproduct/3/", + "protocol": "http", + "host": [ + "uniquedex100", + "iitd", + "site" + ], + "path": [ + "ecommerce", + "deleteaproduct", + "3", + "" + ] + }, + "description": "# _**Delete a Product**_\n\nThis API can be used to detail any product after successfully logging in. It requires a proper Bearer Token which can be generated by going to `ecommerce/api/token` or by using **API for login**. Append the index of the product that you want to delete and send it as a `delete` method." + }, + "response": [] + }, + { + "name": "Purchase a Product", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://uniquedex100.iitd.site/ecommerce/purshaseaproduct/1/", + "protocol": "http", + "host": [ + "uniquedex100", + "iitd", + "site" + ], + "path": [ + "ecommerce", + "purshaseaproduct", + "1", + "" + ] + }, + "description": "# _**Purchase a Product**_\n\nThis API can be used to purchaseany product after successfully logging in. It requires a proper Bearer Token which can be generated by going to `ecommerce/api/token` or by using **API for login**. Append the index of the product that you want to purchase and send it as a `GET` method." + }, + "response": [] + }, + { + "name": "API for Login", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "username", + "value": "aaaa", + "type": "text" + }, + { + "key": "password", + "value": "aaaa", + "type": "text" + } + ] + }, + "url": { + "raw": "http://uniquedex100.iitd.site/api/token/", + "protocol": "http", + "host": [ + "uniquedex100", + "iitd", + "site" + ], + "path": [ + "api", + "token", + "" + ] + }, + "description": "# _**API for Login**_\n\nThis API can be used to get a JSON token in order to use any api like `Add a Product` , `Delete a Product` or `Purchase a Product`.\n\n##### Getting Started\n\nFirst add your `username` and `password` to form data in body of request. They can be created by registering first using `API for Signup`. Then send the request using `post` method\n\n###### To Do Next\n\nThe API returns two tokens namely `Refresh` and `Access`: Use access token to access the above mentioned apis and use the refresh token to regenerate your access token after it expires after 10 minutes." + }, + "response": [] + }, + { + "name": "API for signup", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "username", + "value": "hello1", + "type": "text" + }, + { + "key": "password", + "value": "world", + "type": "text" + }, + { + "key": "", + "value": "", + "type": "text", + "disabled": true + } + ] + }, + "url": { + "raw": "http://uniquedex100.iitd.site/ecommerce/apiforsignup/", + "protocol": "http", + "host": [ + "uniquedex100", + "iitd", + "site" + ], + "path": [ + "ecommerce", + "apiforsignup", + "" + ] + }, + "description": "# _**API for signup**_\n\nThis API can be used to enter your credentials to the server so that you can login in future. In order to signup, provide your username and password in formdata in body and send a `POST` request to the given link." + }, + "response": [] + } + ] +} \ No newline at end of file diff --git a/backend/week3/Scripts/Activate.ps1 b/backend/week3/Scripts/Activate.ps1 new file mode 100644 index 000000000..d3c79649f --- /dev/null +++ b/backend/week3/Scripts/Activate.ps1 @@ -0,0 +1,472 @@ +<# +.Synopsis +Activate a Python virtual environment for the current PowerShell session. + +.Description +Pushes the python executable for a virtual environment to the front of the +$Env:PATH environment variable and sets the prompt to signify that you are +in a Python virtual environment. Makes use of the command line switches as +well as the `pyvenv.cfg` file values present in the virtual environment. + +.Parameter VenvDir +Path to the directory that contains the virtual environment to activate. The +default value for this is the parent of the directory that the Activate.ps1 +script is located within. + +.Parameter Prompt +The prompt prefix to display when this virtual environment is activated. By +default, this prompt is the name of the virtual environment folder (VenvDir) +surrounded by parentheses and followed by a single space (ie. '(.venv) '). + +.Example +Activate.ps1 +Activates the Python virtual environment that contains the Activate.ps1 script. + +.Example +Activate.ps1 -Verbose +Activates the Python virtual environment that contains the Activate.ps1 script, +and shows extra information about the activation as it executes. + +.Example +Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv +Activates the Python virtual environment located in the specified location. + +.Example +Activate.ps1 -Prompt "MyPython" +Activates the Python virtual environment that contains the Activate.ps1 script, +and prefixes the current prompt with the specified string (surrounded in +parentheses) while the virtual environment is active. + +.Notes +On Windows, it may be required to enable this Activate.ps1 script by setting the +execution policy for the user. You can do this by issuing the following PowerShell +command: + +PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + +For more information on Execution Policies: +https://go.microsoft.com/fwlink/?LinkID=135170 + +#> +Param( + [Parameter(Mandatory = $false)] + [String] + $VenvDir, + [Parameter(Mandatory = $false)] + [String] + $Prompt +) + +<# Function declarations --------------------------------------------------- #> + +<# +.Synopsis +Remove all shell session elements added by the Activate script, including the +addition of the virtual environment's Python executable from the beginning of +the PATH variable. + +.Parameter NonDestructive +If present, do not remove this function from the global namespace for the +session. + +#> +function global:deactivate ([switch]$NonDestructive) { + # Revert to original values + + # The prior prompt: + if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { + Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt + Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT + } + + # The prior PYTHONHOME: + if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { + Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME + Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME + } + + # The prior PATH: + if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { + Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH + Remove-Item -Path Env:_OLD_VIRTUAL_PATH + } + + # Just remove the VIRTUAL_ENV altogether: + if (Test-Path -Path Env:VIRTUAL_ENV) { + Remove-Item -Path env:VIRTUAL_ENV + } + + # Just remove VIRTUAL_ENV_PROMPT altogether. + if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) { + Remove-Item -Path env:VIRTUAL_ENV_PROMPT + } + + # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: + if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { + Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force + } + + # Leave deactivate function in the global namespace if requested: + if (-not $NonDestructive) { + Remove-Item -Path function:deactivate + } +} + +<# +.Description +Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the +given folder, and returns them in a map. + +For each line in the pyvenv.cfg file, if that line can be parsed into exactly +two strings separated by `=` (with any amount of whitespace surrounding the =) +then it is considered a `key = value` line. The left hand string is the key, +the right hand is the value. + +If the value starts with a `'` or a `"` then the first and last character is +stripped from the value before being captured. + +.Parameter ConfigDir +Path to the directory that contains the `pyvenv.cfg` file. +#> +function Get-PyVenvConfig( + [String] + $ConfigDir +) { + Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" + + # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). + $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue + + # An empty map will be returned if no config file is found. + $pyvenvConfig = @{ } + + if ($pyvenvConfigPath) { + + Write-Verbose "File exists, parse `key = value` lines" + $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath + + $pyvenvConfigContent | ForEach-Object { + $keyval = $PSItem -split "\s*=\s*", 2 + if ($keyval[0] -and $keyval[1]) { + $val = $keyval[1] + + # Remove extraneous quotations around a string value. + if ("'""".Contains($val.Substring(0, 1))) { + $val = $val.Substring(1, $val.Length - 2) + } + + $pyvenvConfig[$keyval[0]] = $val + Write-Verbose "Adding Key: '$($keyval[0])'='$val'" + } + } + } + return $pyvenvConfig +} + + +<# Begin Activate script --------------------------------------------------- #> + +# Determine the containing directory of this script +$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition +$VenvExecDir = Get-Item -Path $VenvExecPath + +Write-Verbose "Activation script is located in path: '$VenvExecPath'" +Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" +Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" + +# Set values required in priority: CmdLine, ConfigFile, Default +# First, get the location of the virtual environment, it might not be +# VenvExecDir if specified on the command line. +if ($VenvDir) { + Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" +} +else { + Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." + $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") + Write-Verbose "VenvDir=$VenvDir" +} + +# Next, read the `pyvenv.cfg` file to determine any required value such +# as `prompt`. +$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir + +# Next, set the prompt from the command line, or the config file, or +# just use the name of the virtual environment folder. +if ($Prompt) { + Write-Verbose "Prompt specified as argument, using '$Prompt'" +} +else { + Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" + if ($pyvenvCfg -and $pyvenvCfg['prompt']) { + Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" + $Prompt = $pyvenvCfg['prompt']; + } + else { + Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)" + Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" + $Prompt = Split-Path -Path $venvDir -Leaf + } +} + +Write-Verbose "Prompt = '$Prompt'" +Write-Verbose "VenvDir='$VenvDir'" + +# Deactivate any currently active virtual environment, but leave the +# deactivate function in place. +deactivate -nondestructive + +# Now set the environment variable VIRTUAL_ENV, used by many tools to determine +# that there is an activated venv. +$env:VIRTUAL_ENV = $VenvDir + +if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { + + Write-Verbose "Setting prompt to '$Prompt'" + + # Set the prompt to include the env name + # Make sure _OLD_VIRTUAL_PROMPT is global + function global:_OLD_VIRTUAL_PROMPT { "" } + Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT + New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt + + function global:prompt { + Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " + _OLD_VIRTUAL_PROMPT + } + $env:VIRTUAL_ENV_PROMPT = $Prompt +} + +# Clear PYTHONHOME +if (Test-Path -Path Env:PYTHONHOME) { + Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME + Remove-Item -Path Env:PYTHONHOME +} + +# Add the venv to the PATH +Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH +$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" + +# SIG # Begin signature block +# MIIpiQYJKoZIhvcNAQcCoIIpejCCKXYCAQExDzANBglghkgBZQMEAgEFADB5Bgor +# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG +# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBnL745ElCYk8vk +# dBtMuQhLeWJ3ZGfzKW4DHCYzAn+QB6CCDi8wggawMIIEmKADAgECAhAIrUCyYNKc +# TJ9ezam9k67ZMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK +# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV +# BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0z +# NjA0MjgyMzU5NTlaMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg +# SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcg +# UlNBNDA5NiBTSEEzODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +# ggIKAoICAQDVtC9C0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0 +# JAfhS0/TeEP0F9ce2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJr +# Q5qZ8sU7H/Lvy0daE6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhF +# LqGfLOEYwhrMxe6TSXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+F +# LEikVoQ11vkunKoAFdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh +# 3K3kGKDYwSNHR7OhD26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJ +# wZPt4bRc4G/rJvmM1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQay +# g9Rc9hUZTO1i4F4z8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbI +# YViY9XwCFjyDKK05huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchAp +# QfDVxW0mdmgRQRNYmtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRro +# OBl8ZhzNeDhFMJlP/2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IB +# WTCCAVUwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+ +# YXsIiGX0TkIwHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0P +# AQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAk +# BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAC +# hjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9v +# dEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5j +# b20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAED +# MAgGBmeBDAEEATANBgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql +# +Eg08yy25nRm95RysQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFF +# UP2cvbaF4HZ+N3HLIvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1h +# mYFW9snjdufE5BtfQ/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3Ryw +# YFzzDaju4ImhvTnhOE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5Ubdld +# AhQfQDN8A+KVssIhdXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw +# 8MzK7/0pNVwfiThV9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnP +# LqR0kq3bPKSchh/jwVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatE +# QOON8BUozu3xGFYHKi8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bn +# KD+sEq6lLyJsQfmCXBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQji +# WQ1tygVQK+pKHJ6l/aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbq +# yK+p/pQd52MbOoZWeE4wggd3MIIFX6ADAgECAhAHHxQbizANJfMU6yMM0NHdMA0G +# CSqGSIb3DQEBCwUAMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg +# SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcg +# UlNBNDA5NiBTSEEzODQgMjAyMSBDQTEwHhcNMjIwMTE3MDAwMDAwWhcNMjUwMTE1 +# MjM1OTU5WjB8MQswCQYDVQQGEwJVUzEPMA0GA1UECBMGT3JlZ29uMRIwEAYDVQQH +# EwlCZWF2ZXJ0b24xIzAhBgNVBAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9u +# MSMwIQYDVQQDExpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjCCAiIwDQYJKoZI +# hvcNAQEBBQADggIPADCCAgoCggIBAKgc0BTT+iKbtK6f2mr9pNMUTcAJxKdsuOiS +# YgDFfwhjQy89koM7uP+QV/gwx8MzEt3c9tLJvDccVWQ8H7mVsk/K+X+IufBLCgUi +# 0GGAZUegEAeRlSXxxhYScr818ma8EvGIZdiSOhqjYc4KnfgfIS4RLtZSrDFG2tN1 +# 6yS8skFa3IHyvWdbD9PvZ4iYNAS4pjYDRjT/9uzPZ4Pan+53xZIcDgjiTwOh8VGu +# ppxcia6a7xCyKoOAGjvCyQsj5223v1/Ig7Dp9mGI+nh1E3IwmyTIIuVHyK6Lqu35 +# 2diDY+iCMpk9ZanmSjmB+GMVs+H/gOiofjjtf6oz0ki3rb7sQ8fTnonIL9dyGTJ0 +# ZFYKeb6BLA66d2GALwxZhLe5WH4Np9HcyXHACkppsE6ynYjTOd7+jN1PRJahN1oE +# RzTzEiV6nCO1M3U1HbPTGyq52IMFSBM2/07WTJSbOeXjvYR7aUxK9/ZkJiacl2iZ +# I7IWe7JKhHohqKuceQNyOzxTakLcRkzynvIrk33R9YVqtB4L6wtFxhUjvDnQg16x +# ot2KVPdfyPAWd81wtZADmrUtsZ9qG79x1hBdyOl4vUtVPECuyhCxaw+faVjumapP +# Unwo8ygflJJ74J+BYxf6UuD7m8yzsfXWkdv52DjL74TxzuFTLHPyARWCSCAbzn3Z +# Ily+qIqDAgMBAAGjggIGMIICAjAfBgNVHSMEGDAWgBRoN+Drtjv4XxGG+/5hewiI +# ZfROQjAdBgNVHQ4EFgQUt/1Teh2XDuUj2WW3siYWJgkZHA8wDgYDVR0PAQH/BAQD +# AgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMIG1BgNVHR8Ega0wgaowU6BRoE+GTWh0 +# dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWdu +# aW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3JsMFOgUaBPhk1odHRwOi8vY3JsNC5k +# aWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZT +# SEEzODQyMDIxQ0ExLmNybDA+BgNVHSAENzA1MDMGBmeBDAEEATApMCcGCCsGAQUF +# BwIBFhtodHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgZQGCCsGAQUFBwEBBIGH +# MIGEMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wXAYIKwYB +# BQUHMAKGUGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0 +# ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3J0MAwGA1UdEwEB +# /wQCMAAwDQYJKoZIhvcNAQELBQADggIBABxv4AeV/5ltkELHSC63fXAFYS5tadcW +# TiNc2rskrNLrfH1Ns0vgSZFoQxYBFKI159E8oQQ1SKbTEubZ/B9kmHPhprHya08+ +# VVzxC88pOEvz68nA82oEM09584aILqYmj8Pj7h/kmZNzuEL7WiwFa/U1hX+XiWfL +# IJQsAHBla0i7QRF2de8/VSF0XXFa2kBQ6aiTsiLyKPNbaNtbcucaUdn6vVUS5izW +# OXM95BSkFSKdE45Oq3FForNJXjBvSCpwcP36WklaHL+aHu1upIhCTUkzTHMh8b86 +# WmjRUqbrnvdyR2ydI5l1OqcMBjkpPpIV6wcc+KY/RH2xvVuuoHjlUjwq2bHiNoX+ +# W1scCpnA8YTs2d50jDHUgwUo+ciwpffH0Riq132NFmrH3r67VaN3TuBxjI8SIZM5 +# 8WEDkbeoriDk3hxU8ZWV7b8AW6oyVBGfM06UgkfMb58h+tJPrFx8VI/WLq1dTqMf +# ZOm5cuclMnUHs2uqrRNtnV8UfidPBL4ZHkTcClQbCoz0UbLhkiDvIS00Dn+BBcxw +# /TKqVL4Oaz3bkMSsM46LciTeucHY9ExRVt3zy7i149sd+F4QozPqn7FrSVHXmem3 +# r7bjyHTxOgqxRCVa18Vtx7P/8bYSBeS+WHCKcliFCecspusCDSlnRUjZwyPdP0VH +# xaZg2unjHY3rMYIasDCCGqwCAQEwfTBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMO +# RGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgQ29k +# ZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExAhAHHxQbizANJfMU6yMM +# 0NHdMA0GCWCGSAFlAwQCAQUAoIHEMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEE +# MBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCBn +# AZ6P7YvTwq0fbF62o7E75R0LxsW5OtyYiFESQckLhjBYBgorBgEEAYI3AgEMMUow +# SKBGgEQAQgB1AGkAbAB0ADoAIABSAGUAbABlAGEAcwBlAF8AdgAzAC4AMQAxAC4A +# MQBfADIAMAAyADIAMQAyADAANgAuADAAMTANBgkqhkiG9w0BAQEFAASCAgCUdOps +# v3eE2jWZC7R7IKjKvAhB1gqrrqyEOYU6Cy/U9zWWGw8t+HD9dJSqPiUm0mPoRYp8 +# 7DNFKsAGUczwXyI144D50rnrn8qma2mhxw7FmrOcwu+Yw3VYoke9OHy/oiyRKd7s +# NifbuVOepKGHgz/36TTstpclCCd4CsT/nDp1DIZbDYLcJXeRm1dfTM64GRO8JVF5 +# IpYVLoDzzTmj3Jyh+9172T9l/1jymYmanKmXfjnbOTgtpyPZU1RXFYGi/LIl8KXK +# SgPjbN+cWjcTxEOagcKdaDGF6NL+zV0a7cCBkarnTpt9GP5nRXVMFLsphn+9e9R0 +# Rj7z62LPu1U2s9lwCAVFtnECE/5rLu8yGIKKAHNbyb6iX/4EJKeoUc47oXHgJmvB +# 5Ch6oSjTKjSU/bOFDTEO0qIeR7wn7oONu3rjM+2ftVw4hsI1a2+Q0CPP+jMxTAV+ +# Iw1UzNFwbNf6lELnoK0zVSYwcd4pTi1F7/ZRfuo4u+hExkMEY3kz4+7RbeZIuJnJ +# x6WfiyPLOmIqXSm+y9qkBm+TLRVBW4/6ccIeGpSPvsse27YioQ5eZleXJnG4KfpR +# LRRvsq6rhR3a07P0/ZT8H3sP0TY1xOB7KdzTOENXrcAz77t0qYvJhABeKdUAzOyQ +# G3WD2r9CJvyuL8CLYp/xdIqW1yPEOogYW2YE5KGCFz0wghc5BgorBgEEAYI3AwMB +# MYIXKTCCFyUGCSqGSIb3DQEHAqCCFxYwghcSAgEDMQ8wDQYJYIZIAWUDBAIBBQAw +# dwYLKoZIhvcNAQkQAQSgaARmMGQCAQEGCWCGSAGG/WwHATAxMA0GCWCGSAFlAwQC +# AQUABCDl0KR5xtUwOHsKmWo2svZfpRLlEzNgxZDMnLShuhGYmAIQbnZ9CIcvuYaF +# E9nJOOmu7hgPMjAyMjEyMDYyMDA2MjdaoIITBzCCBsAwggSooAMCAQICEAxNaXJL +# lPo8Kko9KQeAPVowDQYJKoZIhvcNAQELBQAwYzELMAkGA1UEBhMCVVMxFzAVBgNV +# BAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0 +# IFJTQTQwOTYgU0hBMjU2IFRpbWVTdGFtcGluZyBDQTAeFw0yMjA5MjEwMDAwMDBa +# Fw0zMzExMjEyMzU5NTlaMEYxCzAJBgNVBAYTAlVTMREwDwYDVQQKEwhEaWdpQ2Vy +# dDEkMCIGA1UEAxMbRGlnaUNlcnQgVGltZXN0YW1wIDIwMjIgLSAyMIICIjANBgkq +# hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAz+ylJjrGqfJru43BDZrboegUhXQzGias +# 0BxVHh42bbySVQxh9J0Jdz0Vlggva2Sk/QaDFteRkjgcMQKW+3KxlzpVrzPsYYrp +# pijbkGNcvYlT4DotjIdCriak5Lt4eLl6FuFWxsC6ZFO7KhbnUEi7iGkMiMbxvuAv +# fTuxylONQIMe58tySSgeTIAehVbnhe3yYbyqOgd99qtu5Wbd4lz1L+2N1E2VhGjj +# gMtqedHSEJFGKes+JvK0jM1MuWbIu6pQOA3ljJRdGVq/9XtAbm8WqJqclUeGhXk+ +# DF5mjBoKJL6cqtKctvdPbnjEKD+jHA9QBje6CNk1prUe2nhYHTno+EyREJZ+TeHd +# wq2lfvgtGx/sK0YYoxn2Off1wU9xLokDEaJLu5i/+k/kezbvBkTkVf826uV8Mefz +# wlLE5hZ7Wn6lJXPbwGqZIS1j5Vn1TS+QHye30qsU5Thmh1EIa/tTQznQZPpWz+D0 +# CuYUbWR4u5j9lMNzIfMvwi4g14Gs0/EH1OG92V1LbjGUKYvmQaRllMBY5eUuKZCm +# t2Fk+tkgbBhRYLqmgQ8JJVPxvzvpqwcOagc5YhnJ1oV/E9mNec9ixezhe7nMZxMH +# msF47caIyLBuMnnHC1mDjcbu9Sx8e47LZInxscS451NeX1XSfRkpWQNO+l3qRXMc +# hH7XzuLUOncCAwEAAaOCAYswggGHMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8E +# AjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMCAGA1UdIAQZMBcwCAYGZ4EMAQQC +# MAsGCWCGSAGG/WwHATAfBgNVHSMEGDAWgBS6FtltTYUvcyl2mi91jGogj57IbzAd +# BgNVHQ4EFgQUYore0GH8jzEU7ZcLzT0qlBTfUpwwWgYDVR0fBFMwUTBPoE2gS4ZJ +# aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5 +# NlNIQTI1NlRpbWVTdGFtcGluZ0NBLmNybDCBkAYIKwYBBQUHAQEEgYMwgYAwJAYI +# KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBYBggrBgEFBQcwAoZM +# aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNB +# NDA5NlNIQTI1NlRpbWVTdGFtcGluZ0NBLmNydDANBgkqhkiG9w0BAQsFAAOCAgEA +# VaoqGvNG83hXNzD8deNP1oUj8fz5lTmbJeb3coqYw3fUZPwV+zbCSVEseIhjVQlG +# OQD8adTKmyn7oz/AyQCbEx2wmIncePLNfIXNU52vYuJhZqMUKkWHSphCK1D8G7We +# CDAJ+uQt1wmJefkJ5ojOfRu4aqKbwVNgCeijuJ3XrR8cuOyYQfD2DoD75P/fnRCn +# 6wC6X0qPGjpStOq/CUkVNTZZmg9U0rIbf35eCa12VIp0bcrSBWcrduv/mLImlTgZ +# iEQU5QpZomvnIj5EIdI/HMCb7XxIstiSDJFPPGaUr10CU+ue4p7k0x+GAWScAMLp +# WnR1DT3heYi/HAGXyRkjgNc2Wl+WFrFjDMZGQDvOXTXUWT5Dmhiuw8nLw/ubE19q +# tcfg8wXDWd8nYiveQclTuf80EGf2JjKYe/5cQpSBlIKdrAqLxksVStOYkEVgM4Dg +# I974A6T2RUflzrgDQkfoQTZxd639ouiXdE4u2h4djFrIHprVwvDGIqhPm73YHJpR +# xC+a9l+nJ5e6li6FV8Bg53hWf2rvwpWaSxECyIKcyRoFfLpxtU56mWz06J7UWpjI +# n7+NuxhcQ/XQKujiYu54BNu90ftbCqhwfvCXhHjjCANdRyxjqCU4lwHSPzra5eX2 +# 5pvcfizM/xdMTQCi2NYBDriL7ubgclWJLCcZYfZ3AYwwggauMIIElqADAgECAhAH +# Nje3JFR82Ees/ShmKl5bMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUw +# EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +# ITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yMjAzMjMwMDAw +# MDBaFw0zNzAzMjIyMzU5NTlaMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdp +# Q2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2 +# IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +# ggIKAoICAQDGhjUGSbPBPXJJUVXHJQPE8pE3qZdRodbSg9GeTKJtoLDMg/la9hGh +# RBVCX6SI82j6ffOciQt/nR+eDzMfUBMLJnOWbfhXqAJ9/UO0hNoR8XOxs+4rgISK +# Ihjf69o9xBd/qxkrPkLcZ47qUT3w1lbU5ygt69OxtXXnHwZljZQp09nsad/ZkIdG +# AHvbREGJ3HxqV3rwN3mfXazL6IRktFLydkf3YYMZ3V+0VAshaG43IbtArF+y3kp9 +# zvU5EmfvDqVjbOSmxR3NNg1c1eYbqMFkdECnwHLFuk4fsbVYTXn+149zk6wsOeKl +# SNbwsDETqVcplicu9Yemj052FVUmcJgmf6AaRyBD40NjgHt1biclkJg6OBGz9vae +# 5jtb7IHeIhTZgirHkr+g3uM+onP65x9abJTyUpURK1h0QCirc0PO30qhHGs4xSnz +# yqqWc0Jon7ZGs506o9UD4L/wojzKQtwYSH8UNM/STKvvmz3+DrhkKvp1KCRB7UK/ +# BZxmSVJQ9FHzNklNiyDSLFc1eSuo80VgvCONWPfcYd6T/jnA+bIwpUzX6ZhKWD7T +# A4j+s4/TXkt2ElGTyYwMO1uKIqjBJgj5FBASA31fI7tk42PgpuE+9sJ0sj8eCXbs +# q11GdeJgo1gJASgADoRU7s7pXcheMBK9Rp6103a50g5rmQzSM7TNsQIDAQABo4IB +# XTCCAVkwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUuhbZbU2FL3Mpdpov +# dYxqII+eyG8wHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0P +# AQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAk +# BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAC +# hjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9v +# dEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5j +# b20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEE +# AjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIBAH1ZjsCTtm+YqUQiAX5m +# 1tghQuGwGC4QTRPPMFPOvxj7x1Bd4ksp+3CKDaopafxpwc8dB+k+YMjYC+VcW9dt +# h/qEICU0MWfNthKWb8RQTGIdDAiCqBa9qVbPFXONASIlzpVpP0d3+3J0FNf/q0+K +# LHqrhc1DX+1gtqpPkWaeLJ7giqzl/Yy8ZCaHbJK9nXzQcAp876i8dU+6WvepELJd +# 6f8oVInw1YpxdmXazPByoyP6wCeCRK6ZJxurJB4mwbfeKuv2nrF5mYGjVoarCkXJ +# 38SNoOeY+/umnXKvxMfBwWpx2cYTgAnEtp/Nh4cku0+jSbl3ZpHxcpzpSwJSpzd+ +# k1OsOx0ISQ+UzTl63f8lY5knLD0/a6fxZsNBzU+2QJshIUDQtxMkzdwdeDrknq3l +# NHGS1yZr5Dhzq6YBT70/O3itTK37xJV77QpfMzmHQXh6OOmc4d0j/R0o08f56PGY +# X/sr2H7yRp11LB4nLCbbbxV7HhmLNriT1ObyF5lZynDwN7+YAN8gFk8n+2BnFqFm +# ut1VwDophrCYoCvtlUG3OtUVmDG0YgkPCr2B2RP+v6TR81fZvAT6gt4y3wSJ8ADN +# XcL50CN/AAvkdgIm2fBldkKmKYcJRyvmfxqkhQ/8mJb2VVQrH4D6wPIOK+XW+6kv +# RBVK5xMOHds3OBqhK/bt1nz8MIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAY +# WjANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNl +# cnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdp +# Q2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcNMzExMTA5 +# MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkw +# FwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVz +# dGVkIFJvb3QgRzQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBz +# aN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbr +# VsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTR +# EEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJ +# z82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyO +# j4DatpGYQJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6R +# AXwhTNS8rhsDdV14Ztk6MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k +# 98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJ +# tppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUa +# dmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZB +# dd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVf +# nSD8oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo4IBOjCCATYwDwYDVR0T +# AQH/BAUwAwEB/zAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wHwYDVR0j +# BBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDgYDVR0PAQH/BAQDAgGGMHkGCCsG +# AQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t +# MEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl +# cnRBc3N1cmVkSURSb290Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9j +# cmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwEQYD +# VR0gBAowCDAGBgRVHSAAMA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXnOF+go3Qb +# PbYW1/e/Vwe9mqyhhyzshV6pGrsi+IcaaVQi7aSId229GhT0E0p6Ly23OO/0/4C5 +# +KH38nLeJLxSA8hO0Cre+i1Wz/n096wwepqLsl7Uz9FDRJtDIeuWcqFItJnLnU+n +# BgMTdydE1Od/6Fmo8L8vC6bp8jQ87PcDx4eo0kxAGTVGamlUsLihVo7spNU96LHc +# /RzY9HdaXFSMb++hUD38dglohJ9vytsgjTVgHAIDyyCwrFigDkBjxZgiwbJZ9VVr +# zyerbHbObyMt9H5xaiNrIv8SuFQtJ37YOtnwtoeW/VvRXKwYw02fc7cBqZ9Xql4o +# 4rmUMYIDdjCCA3ICAQEwdzBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNl +# cnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBT +# SEEyNTYgVGltZVN0YW1waW5nIENBAhAMTWlyS5T6PCpKPSkHgD1aMA0GCWCGSAFl +# AwQCAQUAoIHRMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0B +# CQUxDxcNMjIxMjA2MjAwNjI3WjArBgsqhkiG9w0BCRACDDEcMBowGDAWBBTzhyJN +# hjOCkjWplLy9j5bp/hx8czAvBgkqhkiG9w0BCQQxIgQgjZC+rPrPBAlmFuP+OmvD +# yh8xqQf/ReQsUWtJ8pZa3hUwNwYLKoZIhvcNAQkQAi8xKDAmMCQwIgQgx/ThvjIo +# iSCr4iY6vhrE/E/meBwtZNBMgHVXoCO1tvowDQYJKoZIhvcNAQEBBQAEggIAAgln +# xfP1/ZMQMCTCCrVb3qm7DI8RVNeUM4QEZuxpKvqe9reisD1nem6Z1zKW+5oP7NxF +# /0u8JCTKwkpMZv8m/qcp7TQ3vwHbRqRpNNw/CFd/H0OrLnD14r3jhnNoS/XU0jZi +# U/f9vNl/4qStFMu30yKuxlsycj/At2/ohTZBSWPdv9e+XL3mLZ8HMmwRR5o9Kldg +# p/ErSHOYSqaQLx5/eBF59qtIKsw1WAQITvCW7zTII/gEuCz+myl+7aBAaPrW0mUa +# FVrWQL/Ug3PcwNB7ZK+py7q9eXmQShskSaWXYnl8qCJj4Yex6/D3BMZnDIGXamia +# sH41UoqaeJaqcPvErMyvnCC928552hFjpmEz3PFyVdS04KfjE71CmzDiSNy/jWMM +# W748v6ZnqIGUkYev8D0D4aiZBoYzi4uHuVS7NPCbTakIIbxXeT9Jw1L4xVe6tN+l +# ucDC5UVeuZ8dB2OU+oX0sjTvFRG8V1O2OBBLyNKHtCkFXgpkgFH1Ff/c/XCFgLFV +# ymSCD/LY0EBtJvNUe7EBGM7TWwSVfDNEqz2rAvMERz6F4GRq6MJ5aVfPZ6mx/7qj +# Qs3ScAftPwKYlGJWYmewG+AvHjaHB4Yv1q/19tMjTIiQ4YLk0GaHd6BanFmwpe0f +# Abhwpg6wH7UGifzI6/6kgrdXF80c98cDuAxVg2w= +# SIG # End signature block diff --git a/backend/week3/Scripts/activate b/backend/week3/Scripts/activate new file mode 100644 index 000000000..bb06b290d --- /dev/null +++ b/backend/week3/Scripts/activate @@ -0,0 +1,69 @@ +# This file must be used with "source bin/activate" *from bash* +# you cannot run it directly + +deactivate () { + # reset old environment variables + if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then + PATH="${_OLD_VIRTUAL_PATH:-}" + export PATH + unset _OLD_VIRTUAL_PATH + fi + if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then + PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}" + export PYTHONHOME + unset _OLD_VIRTUAL_PYTHONHOME + fi + + # This should detect bash and zsh, which have a hash command that must + # be called to get it to forget past commands. Without forgetting + # past commands the $PATH changes we made may not be respected + if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then + hash -r 2> /dev/null + fi + + if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then + PS1="${_OLD_VIRTUAL_PS1:-}" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + unset VIRTUAL_ENV + unset VIRTUAL_ENV_PROMPT + if [ ! "${1:-}" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelevant variables +deactivate nondestructive + +VIRTUAL_ENV="C:\src\projectlocationtwo\dsocbackend\backend" +export VIRTUAL_ENV + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/Scripts:$PATH" +export PATH + +# unset PYTHONHOME if set +# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) +# could use `if (set -u; : $PYTHONHOME) ;` in bash +if [ -n "${PYTHONHOME:-}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then + _OLD_VIRTUAL_PS1="${PS1:-}" + PS1="(backend) ${PS1:-}" + export PS1 + VIRTUAL_ENV_PROMPT="(backend) " + export VIRTUAL_ENV_PROMPT +fi + +# This should detect bash and zsh, which have a hash command that must +# be called to get it to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then + hash -r 2> /dev/null +fi diff --git a/backend/week3/Scripts/activate.bat b/backend/week3/Scripts/activate.bat new file mode 100644 index 000000000..4b45a4435 --- /dev/null +++ b/backend/week3/Scripts/activate.bat @@ -0,0 +1,34 @@ +@echo off + +rem This file is UTF-8 encoded, so we need to update the current code page while executing it +for /f "tokens=2 delims=:." %%a in ('"%SystemRoot%\System32\chcp.com"') do ( + set _OLD_CODEPAGE=%%a +) +if defined _OLD_CODEPAGE ( + "%SystemRoot%\System32\chcp.com" 65001 > nul +) + +set VIRTUAL_ENV=C:\src\projectlocationtwo\dsocbackend\backend + +if not defined PROMPT set PROMPT=$P$G + +if defined _OLD_VIRTUAL_PROMPT set PROMPT=%_OLD_VIRTUAL_PROMPT% +if defined _OLD_VIRTUAL_PYTHONHOME set PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME% + +set _OLD_VIRTUAL_PROMPT=%PROMPT% +set PROMPT=(backend) %PROMPT% + +if defined PYTHONHOME set _OLD_VIRTUAL_PYTHONHOME=%PYTHONHOME% +set PYTHONHOME= + +if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH% +if not defined _OLD_VIRTUAL_PATH set _OLD_VIRTUAL_PATH=%PATH% + +set PATH=%VIRTUAL_ENV%\Scripts;%PATH% +set VIRTUAL_ENV_PROMPT=(backend) + +:END +if defined _OLD_CODEPAGE ( + "%SystemRoot%\System32\chcp.com" %_OLD_CODEPAGE% > nul + set _OLD_CODEPAGE= +) diff --git a/backend/week3/Scripts/deactivate.bat b/backend/week3/Scripts/deactivate.bat new file mode 100644 index 000000000..62a39a758 --- /dev/null +++ b/backend/week3/Scripts/deactivate.bat @@ -0,0 +1,22 @@ +@echo off + +if defined _OLD_VIRTUAL_PROMPT ( + set "PROMPT=%_OLD_VIRTUAL_PROMPT%" +) +set _OLD_VIRTUAL_PROMPT= + +if defined _OLD_VIRTUAL_PYTHONHOME ( + set "PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME%" + set _OLD_VIRTUAL_PYTHONHOME= +) + +if defined _OLD_VIRTUAL_PATH ( + set "PATH=%_OLD_VIRTUAL_PATH%" +) + +set _OLD_VIRTUAL_PATH= + +set VIRTUAL_ENV= +set VIRTUAL_ENV_PROMPT= + +:END diff --git a/backend/week3/Scripts/django-admin.exe b/backend/week3/Scripts/django-admin.exe new file mode 100644 index 000000000..0646e39cd Binary files /dev/null and b/backend/week3/Scripts/django-admin.exe differ diff --git a/backend/week3/Scripts/pip.exe b/backend/week3/Scripts/pip.exe new file mode 100644 index 000000000..6c87e93b3 Binary files /dev/null and b/backend/week3/Scripts/pip.exe differ diff --git a/backend/week3/Scripts/pip3.11.exe b/backend/week3/Scripts/pip3.11.exe new file mode 100644 index 000000000..6c87e93b3 Binary files /dev/null and b/backend/week3/Scripts/pip3.11.exe differ diff --git a/backend/week3/Scripts/pip3.exe b/backend/week3/Scripts/pip3.exe new file mode 100644 index 000000000..6c87e93b3 Binary files /dev/null and b/backend/week3/Scripts/pip3.exe differ diff --git a/backend/week3/Scripts/python.exe b/backend/week3/Scripts/python.exe new file mode 100644 index 000000000..4b0ea800c Binary files /dev/null and b/backend/week3/Scripts/python.exe differ diff --git a/backend/week3/Scripts/pythonw.exe b/backend/week3/Scripts/pythonw.exe new file mode 100644 index 000000000..656e19853 Binary files /dev/null and b/backend/week3/Scripts/pythonw.exe differ diff --git a/backend/week3/Scripts/sqlformat.exe b/backend/week3/Scripts/sqlformat.exe new file mode 100644 index 000000000..56494be1e Binary files /dev/null and b/backend/week3/Scripts/sqlformat.exe differ diff --git a/backend/week3/mydjangoproject/ecommerce/__init__.py b/backend/week3/mydjangoproject/ecommerce/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/week3/mydjangoproject/ecommerce/admin.py b/backend/week3/mydjangoproject/ecommerce/admin.py new file mode 100644 index 000000000..0ffaa01bc --- /dev/null +++ b/backend/week3/mydjangoproject/ecommerce/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin + +# Register your models here. +from .models import product +admin.site.register(product) diff --git a/backend/week3/mydjangoproject/ecommerce/apps.py b/backend/week3/mydjangoproject/ecommerce/apps.py new file mode 100644 index 000000000..9a0a30839 --- /dev/null +++ b/backend/week3/mydjangoproject/ecommerce/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class EcommerceConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'ecommerce' diff --git a/backend/week3/mydjangoproject/ecommerce/forms.py b/backend/week3/mydjangoproject/ecommerce/forms.py new file mode 100644 index 000000000..878000c85 --- /dev/null +++ b/backend/week3/mydjangoproject/ecommerce/forms.py @@ -0,0 +1,8 @@ +from django import forms +from .models import product + +class mymodelform(forms.ModelForm): + class Meta: + model = product + fields = ["productIndex", "productName","productPrice","productDescription"] + labels = {"productIndex":"productIndex", "productName":"productName","productPrice":"productPrice","productDescription":"productDescription"} \ No newline at end of file diff --git a/backend/week3/mydjangoproject/ecommerce/migrations/0001_initial.py b/backend/week3/mydjangoproject/ecommerce/migrations/0001_initial.py new file mode 100644 index 000000000..10c24dfc8 --- /dev/null +++ b/backend/week3/mydjangoproject/ecommerce/migrations/0001_initial.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.3 on 2023-07-10 11:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='product', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('productIndex', models.IntegerField(default=0)), + ('productName', models.CharField(max_length=200)), + ('productPrice', models.IntegerField(default=0)), + ('productDescription', models.CharField(max_length=200)), + ], + ), + ] diff --git a/backend/week3/mydjangoproject/ecommerce/migrations/__init__.py b/backend/week3/mydjangoproject/ecommerce/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/week3/mydjangoproject/ecommerce/models.py b/backend/week3/mydjangoproject/ecommerce/models.py new file mode 100644 index 000000000..1714b2a3a --- /dev/null +++ b/backend/week3/mydjangoproject/ecommerce/models.py @@ -0,0 +1,10 @@ +from django.db import models + +# Create your models here. +class product(models.Model): + productIndex = models.IntegerField(default=0) + productName = models.CharField(max_length=200) + productPrice = models.IntegerField(default=0) + productDescription = models.CharField(max_length=200) + def __str__(self): + return self.productName \ No newline at end of file diff --git a/backend/week3/mydjangoproject/ecommerce/serializers.py b/backend/week3/mydjangoproject/ecommerce/serializers.py new file mode 100644 index 000000000..8432fdb37 --- /dev/null +++ b/backend/week3/mydjangoproject/ecommerce/serializers.py @@ -0,0 +1,21 @@ +from rest_framework import serializers +from .models import product +from django.contrib.auth.models import User + + +class ProductSerializers(serializers.ModelSerializer): + class Meta: + model = product + fields = "__all__" + +class UserSerializer(serializers.ModelSerializer): + username = serializers.CharField( + ) + password = serializers.CharField() + + def create(self, validated_data): + user = User.objects.create_user(validated_data['username'],None,validated_data['password']) + return user + class Meta: + model = User + fields = ('id', 'username', 'password') \ No newline at end of file diff --git a/backend/week3/mydjangoproject/ecommerce/templates/ecommerce/addproducts.html b/backend/week3/mydjangoproject/ecommerce/templates/ecommerce/addproducts.html new file mode 100644 index 000000000..a554c95a3 --- /dev/null +++ b/backend/week3/mydjangoproject/ecommerce/templates/ecommerce/addproducts.html @@ -0,0 +1,10 @@ +
+
+
+ Form + {% csrf_token %} + {{ form.as_p }} + +
+
+
\ No newline at end of file diff --git a/backend/week3/mydjangoproject/ecommerce/templates/ecommerce/detail.html b/backend/week3/mydjangoproject/ecommerce/templates/ecommerce/detail.html new file mode 100644 index 000000000..042603dc6 --- /dev/null +++ b/backend/week3/mydjangoproject/ecommerce/templates/ecommerce/detail.html @@ -0,0 +1,6 @@ +

{{ product.productName }}

+
    +{% for choice in product.choice_set.all %} +
  • {{ choice.choice_text }}
  • +{% endfor %} +
\ No newline at end of file diff --git a/backend/week3/mydjangoproject/ecommerce/templates/ecommerce/index.html b/backend/week3/mydjangoproject/ecommerce/templates/ecommerce/index.html new file mode 100644 index 000000000..d98ecc6ec --- /dev/null +++ b/backend/week3/mydjangoproject/ecommerce/templates/ecommerce/index.html @@ -0,0 +1,23 @@ +{% if latest_product_list %} + +{% else %} +

No polls are available.

+{% endif %} +{% block title %}Home{% endblock %} + +{% block content %} +{% if user.is_authenticated %} + Hi {{ user.username }}! +

Log Out

+

Add your products

+{% else %} +

You are not logged in

+ Log In +

Please login to add your products.

+{% endif %} + +{% endblock %} \ No newline at end of file diff --git a/backend/week3/mydjangoproject/ecommerce/templates/ecommerce/register.html b/backend/week3/mydjangoproject/ecommerce/templates/ecommerce/register.html new file mode 100644 index 000000000..8f125845c --- /dev/null +++ b/backend/week3/mydjangoproject/ecommerce/templates/ecommerce/register.html @@ -0,0 +1,20 @@ +
+ {%if messages%} +
    + {%for message in messages%} +
  • {{message}}
  • + {%endfor%} +
+ {%endif%} +

Register to ecommerce

+
+ {% csrf_token %} + + {{ form.as_table }} + + + + +
+
+
\ No newline at end of file diff --git a/backend/week3/mydjangoproject/ecommerce/templates/registration/login.html b/backend/week3/mydjangoproject/ecommerce/templates/registration/login.html new file mode 100644 index 000000000..08e44a97c --- /dev/null +++ b/backend/week3/mydjangoproject/ecommerce/templates/registration/login.html @@ -0,0 +1,6 @@ +

Log In

+
+ {% csrf_token %} + {{ form.as_p }} + +
\ No newline at end of file diff --git a/backend/week3/mydjangoproject/ecommerce/templates/some b/backend/week3/mydjangoproject/ecommerce/templates/some new file mode 100644 index 000000000..e69de29bb diff --git a/backend/week3/mydjangoproject/ecommerce/tests.py b/backend/week3/mydjangoproject/ecommerce/tests.py new file mode 100644 index 000000000..7ce503c2d --- /dev/null +++ b/backend/week3/mydjangoproject/ecommerce/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/backend/week3/mydjangoproject/ecommerce/urls.py b/backend/week3/mydjangoproject/ecommerce/urls.py new file mode 100644 index 000000000..abda1b747 --- /dev/null +++ b/backend/week3/mydjangoproject/ecommerce/urls.py @@ -0,0 +1,18 @@ +from django.urls import path + +from . import views + +urlpatterns = [ + path("", views.index, name="index"), + path("/", views.productDetailView, name="productDetailView"), + path("list/",views.productlistView, name = "productlistview"), + path("register/",views.registerView,name = "registerView"), + path("createProductView/",views.createProductView,name = "createProductView"), + path("getallproducts/",views.getallproducts,name = "getallproducts"), + path("getasingleproduct//",views.getasingleproduct,name = "getasingleproduct"), + path("addaproduct/",views.addaproduct,name = "addaproduct"), + path("deleteaproduct//",views.deleteaproduct,name = "deleteaproduct"), + path("purchaseaproduct//",views.purchaseaproduct,name = "purchaseaproduct"), + path("apiforsignup/",views.apiforsignup,name = "apiforsignup"), + +] \ No newline at end of file diff --git a/backend/week3/mydjangoproject/ecommerce/views.py b/backend/week3/mydjangoproject/ecommerce/views.py new file mode 100644 index 000000000..959c35efc --- /dev/null +++ b/backend/week3/mydjangoproject/ecommerce/views.py @@ -0,0 +1,127 @@ +from django.shortcuts import render,redirect +from django.contrib import messages +from django.contrib.auth.forms import UserCreationForm +from django.contrib.auth import login,authenticate +from django.http import Http404 +from django.http import HttpResponse +from django.template import loader +from .models import product +from .forms import mymodelform +from django.contrib.auth.decorators import login_required +from .serializers import ProductSerializers,UserSerializer +from rest_framework.response import Response +from rest_framework import status +from rest_framework.decorators import api_view,permission_classes +from rest_framework.permissions import IsAuthenticated + +def index(request): + latest_product_list = product.objects.all() + template = loader.get_template("ecommerce/index.html") + context = { + "latest_product_list": latest_product_list, + } + return HttpResponse(template.render(context, request)) + +def productDetailView(request, product_id): + try: + item = product.objects.get(pk = product_id) + except: + raise Http404("Product does not exist.") + return render(request, "ecommerce/detail.html",{"product":item}) + +def productlistView(request): + return HttpResponse("You're at product list view.") + +def registerView(request): + if request.method == 'POST': + form = UserCreationForm(request.POST) + if form.is_valid(): + # username = form.cleaned_data.get('username') + # rawpassword = form.cleaned_data.get('password1') + # user = authenticate(username=username, password=rawpassword) + # login(request, user) + form.save() + print("registered") + return redirect('/ecommerce/') + else: + print("cannot register") + + else: + form = UserCreationForm() + print("ye kya hua") + context = {'form':form} + return render(request,'ecommerce/register.html',context) + +@login_required +def createProductView(request): + if request.method == "POST": + form = mymodelform(request.POST) + if form.is_valid: + form.save() + messages.success("created product successfully!!") + return redirect("ecommerce/addproducts.html") + else : + form = mymodelform() + return render(request,"ecommerce/addproducts.html",{'form':form}) + +# Create your views here. +@api_view(["GET"]) +def getallproducts(request): + if(request.method=='GET'): + products = product.objects.all() + serializers = ProductSerializers(products,many = True) + return Response(serializers.data) + +@api_view(["GET"]) +def getasingleproduct(request,pk): + try: + products = product.objects.get(pk = pk) + except product.DoesNotExist: + return Response(status=status.HTTP_404_NOT_FOUND) + if request.method == "GET": + serializers = ProductSerializers(products) + return Response(serializers.data) + +@api_view(["PUT"]) +@permission_classes((IsAuthenticated, )) +def addaproduct(request): + if request.method == 'PUT': + serializers = ProductSerializers(data=request.data) + if serializers.is_valid(): + serializers.save() + return Response(serializers.data) + return Response(serializers.errors,status=status.HTTP_400_BAD_REQUEST) + +@api_view(["DELETE"]) +@permission_classes((IsAuthenticated, )) +def deleteaproduct(request,pk): + try: + products = product.objects.get(pk=pk) + except product.DoesNotExist: + return Response(status=status.HTTP_404_NOT_FOUND) + if request.method == 'DELETE': + products.delete() + return Response(status=status.HTTP_204_NO_CONTENT) + return Response(status=status.HTTP_404_NOT_FOUND) + +@api_view(["GET"]) +@permission_classes((IsAuthenticated, )) +def purchaseaproduct(request,pk): + try: + products = product.objects.get(pk=pk) + except product.DoesNotExist: + return Response(status=status.HTTP_404_NOT_FOUND) + if request.method == 'GET': + products.delete() + return Response(status=status.HTTP_204_NO_CONTENT) + return Response(status=status.HTTP_404_NOT_FOUND) + +@api_view(["POST"]) +def apiforsignup(request): + if request.method == "POST": + serializers = UserSerializer(data =request.data) + if(serializers.is_valid()): + serializers.save() + return Response(serializers.data,status=status.HTTP_201_CREATED) + return Response(serializers.errors,status=status.HTTP_400_BAD_REQUEST) +#kya bewakoofi hai serializers ke chakkar me django rest use karna pad gaya hai.... \ No newline at end of file diff --git a/backend/week3/mydjangoproject/manage.py b/backend/week3/mydjangoproject/manage.py new file mode 100644 index 000000000..62f3e6225 --- /dev/null +++ b/backend/week3/mydjangoproject/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mydjangoproject.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/backend/week3/mydjangoproject/mydjangoproject/__init__.py b/backend/week3/mydjangoproject/mydjangoproject/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/week3/mydjangoproject/mydjangoproject/asgi.py b/backend/week3/mydjangoproject/mydjangoproject/asgi.py new file mode 100644 index 000000000..7e23598f6 --- /dev/null +++ b/backend/week3/mydjangoproject/mydjangoproject/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for mydjangoproject project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mydjangoproject.settings') + +application = get_asgi_application() diff --git a/backend/week3/mydjangoproject/mydjangoproject/settings.py b/backend/week3/mydjangoproject/mydjangoproject/settings.py new file mode 100644 index 000000000..22234ef1b --- /dev/null +++ b/backend/week3/mydjangoproject/mydjangoproject/settings.py @@ -0,0 +1,125 @@ +""" +Django settings for mydjangoproject project. + +Generated by 'django-admin startproject' using Django 4.2.3. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/4.2/ref/settings/ +""" + +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-1n-l#^()x)p(&k&g-u&o!g-qzohk*a6(25n@q^*f-l+=$yk8jp' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'ecommerce.apps.EcommerceConfig', + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'rest_framework', + 'rest_framework_simplejwt', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'mydjangoproject.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [BASE_DIR/"templates"], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'mydjangoproject.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.2/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'Asia/Kolkata' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.2/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +LOGIN_REDIRECT_URL = "/ecommerce/" +LOGOUT_REDIRECT_URL = "/ecommerce/" + +REST_FRAMEWORK = { + 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'rest_framework_simplejwt.authentication.JWTAuthentication', + ) +} +STATIC_ROOT = "static/" \ No newline at end of file diff --git a/backend/week3/mydjangoproject/mydjangoproject/urls.py b/backend/week3/mydjangoproject/mydjangoproject/urls.py new file mode 100644 index 000000000..c0aa4fef8 --- /dev/null +++ b/backend/week3/mydjangoproject/mydjangoproject/urls.py @@ -0,0 +1,29 @@ +""" +URL configuration for mydjangoproject project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/4.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path,include +from rest_framework_simplejwt.views import TokenObtainPairView,TokenRefreshView + + +urlpatterns = [ + path("ecommerce/", include("ecommerce.urls")), + path("accounts/", include("django.contrib.auth.urls")), + path('admin/', admin.site.urls), + path('api-auth/', include('rest_framework.urls')), + path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), + path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), +] diff --git a/backend/week3/mydjangoproject/mydjangoproject/wsgi.py b/backend/week3/mydjangoproject/mydjangoproject/wsgi.py new file mode 100644 index 000000000..f2f677db2 --- /dev/null +++ b/backend/week3/mydjangoproject/mydjangoproject/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for mydjangoproject project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mydjangoproject.settings') + +application = get_wsgi_application() diff --git a/backend/week3/mydjangoproject/static/admin/css/autocomplete.css b/backend/week3/mydjangoproject/static/admin/css/autocomplete.css new file mode 100644 index 000000000..69c94e734 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/css/autocomplete.css @@ -0,0 +1,275 @@ +select.admin-autocomplete { + width: 20em; +} + +.select2-container--admin-autocomplete.select2-container { + min-height: 30px; +} + +.select2-container--admin-autocomplete .select2-selection--single, +.select2-container--admin-autocomplete .select2-selection--multiple { + min-height: 30px; + padding: 0; +} + +.select2-container--admin-autocomplete.select2-container--focus .select2-selection, +.select2-container--admin-autocomplete.select2-container--open .select2-selection { + border-color: var(--body-quiet-color); + min-height: 30px; +} + +.select2-container--admin-autocomplete.select2-container--focus .select2-selection.select2-selection--single, +.select2-container--admin-autocomplete.select2-container--open .select2-selection.select2-selection--single { + padding: 0; +} + +.select2-container--admin-autocomplete.select2-container--focus .select2-selection.select2-selection--multiple, +.select2-container--admin-autocomplete.select2-container--open .select2-selection.select2-selection--multiple { + padding: 0; +} + +.select2-container--admin-autocomplete .select2-selection--single { + background-color: var(--body-bg); + border: 1px solid var(--border-color); + border-radius: 4px; +} + +.select2-container--admin-autocomplete .select2-selection--single .select2-selection__rendered { + color: var(--body-fg); + line-height: 30px; +} + +.select2-container--admin-autocomplete .select2-selection--single .select2-selection__clear { + cursor: pointer; + float: right; + font-weight: bold; +} + +.select2-container--admin-autocomplete .select2-selection--single .select2-selection__placeholder { + color: var(--body-quiet-color); +} + +.select2-container--admin-autocomplete .select2-selection--single .select2-selection__arrow { + height: 26px; + position: absolute; + top: 1px; + right: 1px; + width: 20px; +} + +.select2-container--admin-autocomplete .select2-selection--single .select2-selection__arrow b { + border-color: #888 transparent transparent transparent; + border-style: solid; + border-width: 5px 4px 0 4px; + height: 0; + left: 50%; + margin-left: -4px; + margin-top: -2px; + position: absolute; + top: 50%; + width: 0; +} + +.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--single .select2-selection__clear { + float: left; +} + +.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--single .select2-selection__arrow { + left: 1px; + right: auto; +} + +.select2-container--admin-autocomplete.select2-container--disabled .select2-selection--single { + background-color: var(--darkened-bg); + cursor: default; +} + +.select2-container--admin-autocomplete.select2-container--disabled .select2-selection--single .select2-selection__clear { + display: none; +} + +.select2-container--admin-autocomplete.select2-container--open .select2-selection--single .select2-selection__arrow b { + border-color: transparent transparent #888 transparent; + border-width: 0 4px 5px 4px; +} + +.select2-container--admin-autocomplete .select2-selection--multiple { + background-color: var(--body-bg); + border: 1px solid var(--border-color); + border-radius: 4px; + cursor: text; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__rendered { + box-sizing: border-box; + list-style: none; + margin: 0; + padding: 0 10px 5px 5px; + width: 100%; + display: flex; + flex-wrap: wrap; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__rendered li { + list-style: none; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__placeholder { + color: var(--body-quiet-color); + margin-top: 5px; + float: left; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__clear { + cursor: pointer; + float: right; + font-weight: bold; + margin: 5px; + position: absolute; + right: 0; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__choice { + background-color: var(--darkened-bg); + border: 1px solid var(--border-color); + border-radius: 4px; + cursor: default; + float: left; + margin-right: 5px; + margin-top: 5px; + padding: 0 5px; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__choice__remove { + color: var(--body-quiet-color); + cursor: pointer; + display: inline-block; + font-weight: bold; + margin-right: 2px; +} + +.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__choice__remove:hover { + color: var(--body-fg); +} + +.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder, .select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-search--inline { + float: right; +} + +.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__choice { + margin-left: 5px; + margin-right: auto; +} + +.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove { + margin-left: 2px; + margin-right: auto; +} + +.select2-container--admin-autocomplete.select2-container--focus .select2-selection--multiple { + border: solid var(--body-quiet-color) 1px; + outline: 0; +} + +.select2-container--admin-autocomplete.select2-container--disabled .select2-selection--multiple { + background-color: var(--darkened-bg); + cursor: default; +} + +.select2-container--admin-autocomplete.select2-container--disabled .select2-selection__choice__remove { + display: none; +} + +.select2-container--admin-autocomplete.select2-container--open.select2-container--above .select2-selection--single, .select2-container--admin-autocomplete.select2-container--open.select2-container--above .select2-selection--multiple { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.select2-container--admin-autocomplete.select2-container--open.select2-container--below .select2-selection--single, .select2-container--admin-autocomplete.select2-container--open.select2-container--below .select2-selection--multiple { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +.select2-container--admin-autocomplete .select2-search--dropdown { + background: var(--darkened-bg); +} + +.select2-container--admin-autocomplete .select2-search--dropdown .select2-search__field { + background: var(--body-bg); + color: var(--body-fg); + border: 1px solid var(--border-color); + border-radius: 4px; +} + +.select2-container--admin-autocomplete .select2-search--inline .select2-search__field { + background: transparent; + color: var(--body-fg); + border: none; + outline: 0; + box-shadow: none; + -webkit-appearance: textfield; +} + +.select2-container--admin-autocomplete .select2-results > .select2-results__options { + max-height: 200px; + overflow-y: auto; + color: var(--body-fg); + background: var(--body-bg); +} + +.select2-container--admin-autocomplete .select2-results__option[role=group] { + padding: 0; +} + +.select2-container--admin-autocomplete .select2-results__option[aria-disabled=true] { + color: var(--body-quiet-color); +} + +.select2-container--admin-autocomplete .select2-results__option[aria-selected=true] { + background-color: var(--selected-bg); + color: var(--body-fg); +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option { + padding-left: 1em; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__group { + padding-left: 0; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option { + margin-left: -1em; + padding-left: 2em; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -2em; + padding-left: 3em; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -3em; + padding-left: 4em; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -4em; + padding-left: 5em; +} + +.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -5em; + padding-left: 6em; +} + +.select2-container--admin-autocomplete .select2-results__option--highlighted[aria-selected] { + background-color: var(--primary); + color: var(--primary-fg); +} + +.select2-container--admin-autocomplete .select2-results__group { + cursor: default; + display: block; + padding: 6px; +} diff --git a/backend/week3/mydjangoproject/static/admin/css/base.css b/backend/week3/mydjangoproject/static/admin/css/base.css new file mode 100644 index 000000000..72f4ae169 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/css/base.css @@ -0,0 +1,1138 @@ +/* + DJANGO Admin styles +*/ + +/* VARIABLE DEFINITIONS */ +html[data-theme="light"], +:root { + --primary: #79aec8; + --secondary: #417690; + --accent: #f5dd5d; + --primary-fg: #fff; + + --body-fg: #333; + --body-bg: #fff; + --body-quiet-color: #666; + --body-loud-color: #000; + + --header-color: #ffc; + --header-branding-color: var(--accent); + --header-bg: var(--secondary); + --header-link-color: var(--primary-fg); + + --breadcrumbs-fg: #c4dce8; + --breadcrumbs-link-fg: var(--body-bg); + --breadcrumbs-bg: var(--primary); + + --link-fg: #417893; + --link-hover-color: #036; + --link-selected-fg: #5b80b2; + + --hairline-color: #e8e8e8; + --border-color: #ccc; + + --error-fg: #ba2121; + + --message-success-bg: #dfd; + --message-warning-bg: #ffc; + --message-error-bg: #ffefef; + + --darkened-bg: #f8f8f8; /* A bit darker than --body-bg */ + --selected-bg: #e4e4e4; /* E.g. selected table cells */ + --selected-row: #ffc; + + --button-fg: #fff; + --button-bg: var(--primary); + --button-hover-bg: #609ab6; + --default-button-bg: var(--secondary); + --default-button-hover-bg: #205067; + --close-button-bg: #747474; + --close-button-hover-bg: #333; + --delete-button-bg: #ba2121; + --delete-button-hover-bg: #a41515; + + --object-tools-fg: var(--button-fg); + --object-tools-bg: var(--close-button-bg); + --object-tools-hover-bg: var(--close-button-hover-bg); + + --font-family-primary: + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + system-ui, + Roboto, + "Helvetica Neue", + Arial, + sans-serif, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol", + "Noto Color Emoji"; + --font-family-monospace: + ui-monospace, + Menlo, + Monaco, + "Cascadia Mono", + "Segoe UI Mono", + "Roboto Mono", + "Oxygen Mono", + "Ubuntu Monospace", + "Source Code Pro", + "Fira Mono", + "Droid Sans Mono", + "Courier New", + monospace, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol", + "Noto Color Emoji"; +} + +html, body { + height: 100%; +} + +body { + margin: 0; + padding: 0; + font-size: 0.875rem; + font-family: var(--font-family-primary); + color: var(--body-fg); + background: var(--body-bg); +} + +/* LINKS */ + +a:link, a:visited { + color: var(--link-fg); + text-decoration: none; + transition: color 0.15s, background 0.15s; +} + +a:focus, a:hover { + color: var(--link-hover-color); +} + +a:focus { + text-decoration: underline; +} + +a img { + border: none; +} + +a.section:link, a.section:visited { + color: var(--header-link-color); + text-decoration: none; +} + +a.section:focus, a.section:hover { + text-decoration: underline; +} + +/* GLOBAL DEFAULTS */ + +p, ol, ul, dl { + margin: .2em 0 .8em 0; +} + +p { + padding: 0; + line-height: 140%; +} + +h1,h2,h3,h4,h5 { + font-weight: bold; +} + +h1 { + margin: 0 0 20px; + font-weight: 300; + font-size: 1.25rem; + color: var(--body-quiet-color); +} + +h2 { + font-size: 1rem; + margin: 1em 0 .5em 0; +} + +h2.subhead { + font-weight: normal; + margin-top: 0; +} + +h3 { + font-size: 0.875rem; + margin: .8em 0 .3em 0; + color: var(--body-quiet-color); + font-weight: bold; +} + +h4 { + font-size: 0.75rem; + margin: 1em 0 .8em 0; + padding-bottom: 3px; +} + +h5 { + font-size: 0.625rem; + margin: 1.5em 0 .5em 0; + color: var(--body-quiet-color); + text-transform: uppercase; + letter-spacing: 1px; +} + +ul > li { + list-style-type: square; + padding: 1px 0; +} + +li ul { + margin-bottom: 0; +} + +li, dt, dd { + font-size: 0.8125rem; + line-height: 1.25rem; +} + +dt { + font-weight: bold; + margin-top: 4px; +} + +dd { + margin-left: 0; +} + +form { + margin: 0; + padding: 0; +} + +fieldset { + margin: 0; + min-width: 0; + padding: 0; + border: none; + border-top: 1px solid var(--hairline-color); +} + +blockquote { + font-size: 0.6875rem; + color: #777; + margin-left: 2px; + padding-left: 10px; + border-left: 5px solid #ddd; +} + +code, pre { + font-family: var(--font-family-monospace); + color: var(--body-quiet-color); + font-size: 0.75rem; + overflow-x: auto; +} + +pre.literal-block { + margin: 10px; + background: var(--darkened-bg); + padding: 6px 8px; +} + +code strong { + color: #930; +} + +hr { + clear: both; + color: var(--hairline-color); + background-color: var(--hairline-color); + height: 1px; + border: none; + margin: 0; + padding: 0; + line-height: 1px; +} + +/* TEXT STYLES & MODIFIERS */ + +.small { + font-size: 0.6875rem; +} + +.mini { + font-size: 0.625rem; +} + +.help, p.help, form p.help, div.help, form div.help, div.help li { + font-size: 0.6875rem; + color: var(--body-quiet-color); +} + +div.help ul { + margin-bottom: 0; +} + +.help-tooltip { + cursor: help; +} + +p img, h1 img, h2 img, h3 img, h4 img, td img { + vertical-align: middle; +} + +.quiet, a.quiet:link, a.quiet:visited { + color: var(--body-quiet-color); + font-weight: normal; +} + +.clear { + clear: both; +} + +.nowrap { + white-space: nowrap; +} + +.hidden { + display: none !important; +} + +/* TABLES */ + +table { + border-collapse: collapse; + border-color: var(--border-color); +} + +td, th { + font-size: 0.8125rem; + line-height: 1rem; + border-bottom: 1px solid var(--hairline-color); + vertical-align: top; + padding: 8px; +} + +th { + font-weight: 600; + text-align: left; +} + +thead th, +tfoot td { + color: var(--body-quiet-color); + padding: 5px 10px; + font-size: 0.6875rem; + background: var(--body-bg); + border: none; + border-top: 1px solid var(--hairline-color); + border-bottom: 1px solid var(--hairline-color); +} + +tfoot td { + border-bottom: none; + border-top: 1px solid var(--hairline-color); +} + +thead th.required { + color: var(--body-loud-color); +} + +tr.alt { + background: var(--darkened-bg); +} + +tr:nth-child(odd), .row-form-errors { + background: var(--body-bg); +} + +tr:nth-child(even), +tr:nth-child(even) .errorlist, +tr:nth-child(odd) + .row-form-errors, +tr:nth-child(odd) + .row-form-errors .errorlist { + background: var(--darkened-bg); +} + +/* SORTABLE TABLES */ + +thead th { + padding: 5px 10px; + line-height: normal; + text-transform: uppercase; + background: var(--darkened-bg); +} + +thead th a:link, thead th a:visited { + color: var(--body-quiet-color); +} + +thead th.sorted { + background: var(--selected-bg); +} + +thead th.sorted .text { + padding-right: 42px; +} + +table thead th .text span { + padding: 8px 10px; + display: block; +} + +table thead th .text a { + display: block; + cursor: pointer; + padding: 8px 10px; +} + +table thead th .text a:focus, table thead th .text a:hover { + background: var(--selected-bg); +} + +thead th.sorted a.sortremove { + visibility: hidden; +} + +table thead th.sorted:hover a.sortremove { + visibility: visible; +} + +table thead th.sorted .sortoptions { + display: block; + padding: 9px 5px 0 5px; + float: right; + text-align: right; +} + +table thead th.sorted .sortpriority { + font-size: .8em; + min-width: 12px; + text-align: center; + vertical-align: 3px; + margin-left: 2px; + margin-right: 2px; +} + +table thead th.sorted .sortoptions a { + position: relative; + width: 14px; + height: 14px; + display: inline-block; + background: url(../img/sorting-icons.svg) 0 0 no-repeat; + background-size: 14px auto; +} + +table thead th.sorted .sortoptions a.sortremove { + background-position: 0 0; +} + +table thead th.sorted .sortoptions a.sortremove:after { + content: '\\'; + position: absolute; + top: -6px; + left: 3px; + font-weight: 200; + font-size: 1.125rem; + color: var(--body-quiet-color); +} + +table thead th.sorted .sortoptions a.sortremove:focus:after, +table thead th.sorted .sortoptions a.sortremove:hover:after { + color: var(--link-fg); +} + +table thead th.sorted .sortoptions a.sortremove:focus, +table thead th.sorted .sortoptions a.sortremove:hover { + background-position: 0 -14px; +} + +table thead th.sorted .sortoptions a.ascending { + background-position: 0 -28px; +} + +table thead th.sorted .sortoptions a.ascending:focus, +table thead th.sorted .sortoptions a.ascending:hover { + background-position: 0 -42px; +} + +table thead th.sorted .sortoptions a.descending { + top: 1px; + background-position: 0 -56px; +} + +table thead th.sorted .sortoptions a.descending:focus, +table thead th.sorted .sortoptions a.descending:hover { + background-position: 0 -70px; +} + +/* FORM DEFAULTS */ + +input, textarea, select, .form-row p, form .button { + margin: 2px 0; + padding: 2px 3px; + vertical-align: middle; + font-family: var(--font-family-primary); + font-weight: normal; + font-size: 0.8125rem; +} +.form-row div.help { + padding: 2px 3px; +} + +textarea { + vertical-align: top; +} + +input[type=text], input[type=password], input[type=email], input[type=url], +input[type=number], input[type=tel], textarea, select, .vTextField { + border: 1px solid var(--border-color); + border-radius: 4px; + padding: 5px 6px; + margin-top: 0; + color: var(--body-fg); + background-color: var(--body-bg); +} + +input[type=text]:focus, input[type=password]:focus, input[type=email]:focus, +input[type=url]:focus, input[type=number]:focus, input[type=tel]:focus, +textarea:focus, select:focus, .vTextField:focus { + border-color: var(--body-quiet-color); +} + +select { + height: 1.875rem; +} + +select[multiple] { + /* Allow HTML size attribute to override the height in the rule above. */ + height: auto; + min-height: 150px; +} + +/* FORM BUTTONS */ + +.button, input[type=submit], input[type=button], .submit-row input, a.button { + background: var(--button-bg); + padding: 10px 15px; + border: none; + border-radius: 4px; + color: var(--button-fg); + cursor: pointer; + transition: background 0.15s; +} + +a.button { + padding: 4px 5px; +} + +.button:active, input[type=submit]:active, input[type=button]:active, +.button:focus, input[type=submit]:focus, input[type=button]:focus, +.button:hover, input[type=submit]:hover, input[type=button]:hover { + background: var(--button-hover-bg); +} + +.button[disabled], input[type=submit][disabled], input[type=button][disabled] { + opacity: 0.4; +} + +.button.default, input[type=submit].default, .submit-row input.default { + border: none; + font-weight: 400; + background: var(--default-button-bg); +} + +.button.default:active, input[type=submit].default:active, +.button.default:focus, input[type=submit].default:focus, +.button.default:hover, input[type=submit].default:hover { + background: var(--default-button-hover-bg); +} + +.button[disabled].default, +input[type=submit][disabled].default, +input[type=button][disabled].default { + opacity: 0.4; +} + + +/* MODULES */ + +.module { + border: none; + margin-bottom: 30px; + background: var(--body-bg); +} + +.module p, .module ul, .module h3, .module h4, .module dl, .module pre { + padding-left: 10px; + padding-right: 10px; +} + +.module blockquote { + margin-left: 12px; +} + +.module ul, .module ol { + margin-left: 1.5em; +} + +.module h3 { + margin-top: .6em; +} + +.module h2, .module caption, .inline-group h2 { + margin: 0; + padding: 8px; + font-weight: 400; + font-size: 0.8125rem; + text-align: left; + background: var(--primary); + color: var(--header-link-color); +} + +.module caption, +.inline-group h2 { + font-size: 0.75rem; + letter-spacing: 0.5px; + text-transform: uppercase; +} + +.module table { + border-collapse: collapse; +} + +/* MESSAGES & ERRORS */ + +ul.messagelist { + padding: 0; + margin: 0; +} + +ul.messagelist li { + display: block; + font-weight: 400; + font-size: 0.8125rem; + padding: 10px 10px 10px 65px; + margin: 0 0 10px 0; + background: var(--message-success-bg) url(../img/icon-yes.svg) 40px 12px no-repeat; + background-size: 16px auto; + color: var(--body-fg); + word-break: break-word; +} + +ul.messagelist li.warning { + background: var(--message-warning-bg) url(../img/icon-alert.svg) 40px 14px no-repeat; + background-size: 14px auto; +} + +ul.messagelist li.error { + background: var(--message-error-bg) url(../img/icon-no.svg) 40px 12px no-repeat; + background-size: 16px auto; +} + +.errornote { + font-size: 0.875rem; + font-weight: 700; + display: block; + padding: 10px 12px; + margin: 0 0 10px 0; + color: var(--error-fg); + border: 1px solid var(--error-fg); + border-radius: 4px; + background-color: var(--body-bg); + background-position: 5px 12px; + overflow-wrap: break-word; +} + +ul.errorlist { + margin: 0 0 4px; + padding: 0; + color: var(--error-fg); + background: var(--body-bg); +} + +ul.errorlist li { + font-size: 0.8125rem; + display: block; + margin-bottom: 4px; + overflow-wrap: break-word; +} + +ul.errorlist li:first-child { + margin-top: 0; +} + +ul.errorlist li a { + color: inherit; + text-decoration: underline; +} + +td ul.errorlist { + margin: 0; + padding: 0; +} + +td ul.errorlist li { + margin: 0; +} + +.form-row.errors { + margin: 0; + border: none; + border-bottom: 1px solid var(--hairline-color); + background: none; +} + +.form-row.errors ul.errorlist li { + padding-left: 0; +} + +.errors input, .errors select, .errors textarea, +td ul.errorlist + input, td ul.errorlist + select, td ul.errorlist + textarea { + border: 1px solid var(--error-fg); +} + +.description { + font-size: 0.75rem; + padding: 5px 0 0 12px; +} + +/* BREADCRUMBS */ + +div.breadcrumbs { + background: var(--breadcrumbs-bg); + padding: 10px 40px; + border: none; + color: var(--breadcrumbs-fg); + text-align: left; +} + +div.breadcrumbs a { + color: var(--breadcrumbs-link-fg); +} + +div.breadcrumbs a:focus, div.breadcrumbs a:hover { + color: var(--breadcrumbs-fg); +} + +/* ACTION ICONS */ + +.viewlink, .inlineviewlink { + padding-left: 16px; + background: url(../img/icon-viewlink.svg) 0 1px no-repeat; +} + +.addlink { + padding-left: 16px; + background: url(../img/icon-addlink.svg) 0 1px no-repeat; +} + +.changelink, .inlinechangelink { + padding-left: 16px; + background: url(../img/icon-changelink.svg) 0 1px no-repeat; +} + +.deletelink { + padding-left: 16px; + background: url(../img/icon-deletelink.svg) 0 1px no-repeat; +} + +a.deletelink:link, a.deletelink:visited { + color: #CC3434; /* XXX Probably unused? */ +} + +a.deletelink:focus, a.deletelink:hover { + color: #993333; /* XXX Probably unused? */ + text-decoration: none; +} + +/* OBJECT TOOLS */ + +.object-tools { + font-size: 0.625rem; + font-weight: bold; + padding-left: 0; + float: right; + position: relative; + margin-top: -48px; +} + +.object-tools li { + display: block; + float: left; + margin-left: 5px; + height: 1rem; +} + +.object-tools a { + border-radius: 15px; +} + +.object-tools a:link, .object-tools a:visited { + display: block; + float: left; + padding: 3px 12px; + background: var(--object-tools-bg); + color: var(--object-tools-fg); + font-weight: 400; + font-size: 0.6875rem; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.object-tools a:focus, .object-tools a:hover { + background-color: var(--object-tools-hover-bg); +} + +.object-tools a:focus{ + text-decoration: none; +} + +.object-tools a.viewsitelink, .object-tools a.addlink { + background-repeat: no-repeat; + background-position: right 7px center; + padding-right: 26px; +} + +.object-tools a.viewsitelink { + background-image: url(../img/tooltag-arrowright.svg); +} + +.object-tools a.addlink { + background-image: url(../img/tooltag-add.svg); +} + +/* OBJECT HISTORY */ + +#change-history table { + width: 100%; +} + +#change-history table tbody th { + width: 16em; +} + +#change-history .paginator { + color: var(--body-quiet-color); + border-bottom: 1px solid var(--hairline-color); + background: var(--body-bg); + overflow: hidden; +} + +/* PAGE STRUCTURE */ + +#container { + position: relative; + width: 100%; + min-width: 980px; + padding: 0; + display: flex; + flex-direction: column; + height: 100%; +} + +#container > div { + flex-shrink: 0; +} + +#container > .main { + display: flex; + flex: 1 0 auto; +} + +.main > .content { + flex: 1 0; + max-width: 100%; +} + +.skip-to-content-link { + position: absolute; + top: -999px; + margin: 5px; + padding: 5px; + background: var(--body-bg); + z-index: 1; +} + +.skip-to-content-link:focus { + left: 0px; + top: 0px; +} + +#content { + padding: 20px 40px; +} + +.dashboard #content { + width: 600px; +} + +#content-main { + float: left; + width: 100%; +} + +#content-related { + float: right; + width: 260px; + position: relative; + margin-right: -300px; +} + +#footer { + clear: both; + padding: 10px; +} + +/* COLUMN TYPES */ + +.colMS { + margin-right: 300px; +} + +.colSM { + margin-left: 300px; +} + +.colSM #content-related { + float: left; + margin-right: 0; + margin-left: -300px; +} + +.colSM #content-main { + float: right; +} + +.popup .colM { + width: auto; +} + +/* HEADER */ + +#header { + width: auto; + height: auto; + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 40px; + background: var(--header-bg); + color: var(--header-color); + overflow: hidden; +} + +#header a:link, #header a:visited, #logout-form button { + color: var(--header-link-color); +} + +#header a:focus , #header a:hover { + text-decoration: underline; +} + +#branding { + display: flex; +} + +#branding h1 { + padding: 0; + margin: 0; + margin-inline-end: 20px; + font-weight: 300; + font-size: 1.5rem; + color: var(--header-branding-color); +} + +#branding h1 a:link, #branding h1 a:visited { + color: var(--accent); +} + +#branding h2 { + padding: 0 10px; + font-size: 0.875rem; + margin: -8px 0 8px 0; + font-weight: normal; + color: var(--header-color); +} + +#branding a:hover { + text-decoration: none; +} + +#logout-form { + display: inline; +} + +#logout-form button { + background: none; + border: 0; + cursor: pointer; + font-family: var(--font-family-primary); +} + +#user-tools { + float: right; + margin: 0 0 0 20px; + text-align: right; +} + +#user-tools, #logout-form button{ + padding: 0; + font-weight: 300; + font-size: 0.6875rem; + letter-spacing: 0.5px; + text-transform: uppercase; +} + +#user-tools a, #logout-form button { + border-bottom: 1px solid rgba(255, 255, 255, 0.25); +} + +#user-tools a:focus, #user-tools a:hover, +#logout-form button:active, #logout-form button:hover { + text-decoration: none; + border-bottom: 0; +} + +#logout-form button:active, #logout-form button:hover { + margin-bottom: 1px; +} + +/* SIDEBAR */ + +#content-related { + background: var(--darkened-bg); +} + +#content-related .module { + background: none; +} + +#content-related h3 { + color: var(--body-quiet-color); + padding: 0 16px; + margin: 0 0 16px; +} + +#content-related h4 { + font-size: 0.8125rem; +} + +#content-related p { + padding-left: 16px; + padding-right: 16px; +} + +#content-related .actionlist { + padding: 0; + margin: 16px; +} + +#content-related .actionlist li { + line-height: 1.2; + margin-bottom: 10px; + padding-left: 18px; +} + +#content-related .module h2 { + background: none; + padding: 16px; + margin-bottom: 16px; + border-bottom: 1px solid var(--hairline-color); + font-size: 1.125rem; + color: var(--body-fg); +} + +.delete-confirmation form input[type="submit"] { + background: var(--delete-button-bg); + border-radius: 4px; + padding: 10px 15px; + color: var(--button-fg); +} + +.delete-confirmation form input[type="submit"]:active, +.delete-confirmation form input[type="submit"]:focus, +.delete-confirmation form input[type="submit"]:hover { + background: var(--delete-button-hover-bg); +} + +.delete-confirmation form .cancel-link { + display: inline-block; + vertical-align: middle; + height: 0.9375rem; + line-height: 0.9375rem; + border-radius: 4px; + padding: 10px 15px; + color: var(--button-fg); + background: var(--close-button-bg); + margin: 0 0 0 10px; +} + +.delete-confirmation form .cancel-link:active, +.delete-confirmation form .cancel-link:focus, +.delete-confirmation form .cancel-link:hover { + background: var(--close-button-hover-bg); +} + +/* POPUP */ +.popup #content { + padding: 20px; +} + +.popup #container { + min-width: 0; +} + +.popup #header { + padding: 10px 20px; +} + +/* PAGINATOR */ + +.paginator { + font-size: 0.8125rem; + padding-top: 10px; + padding-bottom: 10px; + line-height: 22px; + margin: 0; + border-top: 1px solid var(--hairline-color); + width: 100%; +} + +.paginator a:link, .paginator a:visited { + padding: 2px 6px; + background: var(--button-bg); + text-decoration: none; + color: var(--button-fg); +} + +.paginator a.showall { + border: none; + background: none; + color: var(--link-fg); +} + +.paginator a.showall:focus, .paginator a.showall:hover { + background: none; + color: var(--link-hover-color); +} + +.paginator .end { + margin-right: 6px; +} + +.paginator .this-page { + padding: 2px 6px; + font-weight: bold; + font-size: 0.8125rem; + vertical-align: top; +} + +.paginator a:focus, .paginator a:hover { + color: white; + background: var(--link-hover-color); +} + +.base-svgs { + display: none; +} diff --git a/backend/week3/mydjangoproject/static/admin/css/changelists.css b/backend/week3/mydjangoproject/static/admin/css/changelists.css new file mode 100644 index 000000000..a7545131a --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/css/changelists.css @@ -0,0 +1,328 @@ +/* CHANGELISTS */ + +#changelist { + display: flex; + align-items: flex-start; + justify-content: space-between; +} + +#changelist .changelist-form-container { + flex: 1 1 auto; + min-width: 0; +} + +#changelist table { + width: 100%; +} + +.change-list .hiddenfields { display:none; } + +.change-list .filtered table { + border-right: none; +} + +.change-list .filtered { + min-height: 400px; +} + +.change-list .filtered .results, .change-list .filtered .paginator, +.filtered #toolbar, .filtered div.xfull { + width: auto; +} + +.change-list .filtered table tbody th { + padding-right: 1em; +} + +#changelist-form .results { + overflow-x: auto; + width: 100%; +} + +#changelist .toplinks { + border-bottom: 1px solid var(--hairline-color); +} + +#changelist .paginator { + color: var(--body-quiet-color); + border-bottom: 1px solid var(--hairline-color); + background: var(--body-bg); + overflow: hidden; +} + +/* CHANGELIST TABLES */ + +#changelist table thead th { + padding: 0; + white-space: nowrap; + vertical-align: middle; +} + +#changelist table thead th.action-checkbox-column { + width: 1.5em; + text-align: center; +} + +#changelist table tbody td.action-checkbox { + text-align: center; +} + +#changelist table tfoot { + color: var(--body-quiet-color); +} + +/* TOOLBAR */ + +#toolbar { + padding: 8px 10px; + margin-bottom: 15px; + border-top: 1px solid var(--hairline-color); + border-bottom: 1px solid var(--hairline-color); + background: var(--darkened-bg); + color: var(--body-quiet-color); +} + +#toolbar form input { + border-radius: 4px; + font-size: 0.875rem; + padding: 5px; + color: var(--body-fg); +} + +#toolbar #searchbar { + height: 1.1875rem; + border: 1px solid var(--border-color); + padding: 2px 5px; + margin: 0; + vertical-align: top; + font-size: 0.8125rem; + max-width: 100%; +} + +#toolbar #searchbar:focus { + border-color: var(--body-quiet-color); +} + +#toolbar form input[type="submit"] { + border: 1px solid var(--border-color); + font-size: 0.8125rem; + padding: 4px 8px; + margin: 0; + vertical-align: middle; + background: var(--body-bg); + box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset; + cursor: pointer; + color: var(--body-fg); +} + +#toolbar form input[type="submit"]:focus, +#toolbar form input[type="submit"]:hover { + border-color: var(--body-quiet-color); +} + +#changelist-search img { + vertical-align: middle; + margin-right: 4px; +} + +#changelist-search .help { + word-break: break-word; +} + +/* FILTER COLUMN */ + +#changelist-filter { + flex: 0 0 240px; + order: 1; + background: var(--darkened-bg); + border-left: none; + margin: 0 0 0 30px; +} + +#changelist-filter h2 { + font-size: 0.875rem; + text-transform: uppercase; + letter-spacing: 0.5px; + padding: 5px 15px; + margin-bottom: 12px; + border-bottom: none; +} + +#changelist-filter h3, +#changelist-filter details summary { + font-weight: 400; + padding: 0 15px; + margin-bottom: 10px; +} + +#changelist-filter details summary > * { + display: inline; +} + +#changelist-filter details > summary { + list-style-type: none; +} + +#changelist-filter details > summary::-webkit-details-marker { + display: none; +} + +#changelist-filter details > summary::before { + content: '→'; + font-weight: bold; + color: var(--link-hover-color); +} + +#changelist-filter details[open] > summary::before { + content: '↓'; +} + +#changelist-filter ul { + margin: 5px 0; + padding: 0 15px 15px; + border-bottom: 1px solid var(--hairline-color); +} + +#changelist-filter ul:last-child { + border-bottom: none; +} + +#changelist-filter li { + list-style-type: none; + margin-left: 0; + padding-left: 0; +} + +#changelist-filter a { + display: block; + color: var(--body-quiet-color); + word-break: break-word; +} + +#changelist-filter li.selected { + border-left: 5px solid var(--hairline-color); + padding-left: 10px; + margin-left: -15px; +} + +#changelist-filter li.selected a { + color: var(--link-selected-fg); +} + +#changelist-filter a:focus, #changelist-filter a:hover, +#changelist-filter li.selected a:focus, +#changelist-filter li.selected a:hover { + color: var(--link-hover-color); +} + +#changelist-filter #changelist-filter-clear a { + font-size: 0.8125rem; + padding-bottom: 10px; + border-bottom: 1px solid var(--hairline-color); +} + +/* DATE DRILLDOWN */ + +.change-list .toplinks { + display: flex; + padding-bottom: 5px; + flex-wrap: wrap; + gap: 3px 17px; + font-weight: bold; +} + +.change-list .toplinks a { + font-size: 0.8125rem; +} + +.change-list .toplinks .date-back { + color: var(--body-quiet-color); +} + +.change-list .toplinks .date-back:focus, +.change-list .toplinks .date-back:hover { + color: var(--link-hover-color); +} + +/* ACTIONS */ + +.filtered .actions { + border-right: none; +} + +#changelist table input { + margin: 0; + vertical-align: baseline; +} + +/* Once the :has() pseudo-class is supported by all browsers, the tr.selected + selector and the JS adding the class can be removed. */ +#changelist tbody tr.selected { + background-color: var(--selected-row); +} + +#changelist tbody tr:has(.action-select:checked) { + background-color: var(--selected-row); +} + +#changelist .actions { + padding: 10px; + background: var(--body-bg); + border-top: none; + border-bottom: none; + line-height: 1.5rem; + color: var(--body-quiet-color); + width: 100%; +} + +#changelist .actions span.all, +#changelist .actions span.action-counter, +#changelist .actions span.clear, +#changelist .actions span.question { + font-size: 0.8125rem; + margin: 0 0.5em; +} + +#changelist .actions:last-child { + border-bottom: none; +} + +#changelist .actions select { + vertical-align: top; + height: 1.5rem; + color: var(--body-fg); + border: 1px solid var(--border-color); + border-radius: 4px; + font-size: 0.875rem; + padding: 0 0 0 4px; + margin: 0; + margin-left: 10px; +} + +#changelist .actions select:focus { + border-color: var(--body-quiet-color); +} + +#changelist .actions label { + display: inline-block; + vertical-align: middle; + font-size: 0.8125rem; +} + +#changelist .actions .button { + font-size: 0.8125rem; + border: 1px solid var(--border-color); + border-radius: 4px; + background: var(--body-bg); + box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset; + cursor: pointer; + height: 1.5rem; + line-height: 1; + padding: 4px 8px; + margin: 0; + color: var(--body-fg); +} + +#changelist .actions .button:focus, #changelist .actions .button:hover { + border-color: var(--body-quiet-color); +} diff --git a/backend/week3/mydjangoproject/static/admin/css/dark_mode.css b/backend/week3/mydjangoproject/static/admin/css/dark_mode.css new file mode 100644 index 000000000..6d08233aa --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/css/dark_mode.css @@ -0,0 +1,137 @@ +@media (prefers-color-scheme: dark) { + :root { + --primary: #264b5d; + --primary-fg: #f7f7f7; + + --body-fg: #eeeeee; + --body-bg: #121212; + --body-quiet-color: #e0e0e0; + --body-loud-color: #ffffff; + + --breadcrumbs-link-fg: #e0e0e0; + --breadcrumbs-bg: var(--primary); + + --link-fg: #81d4fa; + --link-hover-color: #4ac1f7; + --link-selected-fg: #6f94c6; + + --hairline-color: #272727; + --border-color: #353535; + + --error-fg: #e35f5f; + --message-success-bg: #006b1b; + --message-warning-bg: #583305; + --message-error-bg: #570808; + + --darkened-bg: #212121; + --selected-bg: #1b1b1b; + --selected-row: #00363a; + + --close-button-bg: #333333; + --close-button-hover-bg: #666666; + } + } + + +html[data-theme="dark"] { + --primary: #264b5d; + --primary-fg: #f7f7f7; + + --body-fg: #eeeeee; + --body-bg: #121212; + --body-quiet-color: #e0e0e0; + --body-loud-color: #ffffff; + + --breadcrumbs-link-fg: #e0e0e0; + --breadcrumbs-bg: var(--primary); + + --link-fg: #81d4fa; + --link-hover-color: #4ac1f7; + --link-selected-fg: #6f94c6; + + --hairline-color: #272727; + --border-color: #353535; + + --error-fg: #e35f5f; + --message-success-bg: #006b1b; + --message-warning-bg: #583305; + --message-error-bg: #570808; + + --darkened-bg: #212121; + --selected-bg: #1b1b1b; + --selected-row: #00363a; + + --close-button-bg: #333333; + --close-button-hover-bg: #666666; +} + +/* THEME SWITCH */ +.theme-toggle { + cursor: pointer; + border: none; + padding: 0; + background: transparent; + vertical-align: middle; + margin-inline-start: 5px; + margin-top: -1px; +} + +.theme-toggle svg { + vertical-align: middle; + height: 1rem; + width: 1rem; + display: none; +} + +/* +Fully hide screen reader text so we only show the one matching the current +theme. +*/ +.theme-toggle .visually-hidden { + display: none; +} + +html[data-theme="auto"] .theme-toggle .theme-label-when-auto { + display: block; +} + +html[data-theme="dark"] .theme-toggle .theme-label-when-dark { + display: block; +} + +html[data-theme="light"] .theme-toggle .theme-label-when-light { + display: block; +} + +/* ICONS */ +.theme-toggle svg.theme-icon-when-auto, +.theme-toggle svg.theme-icon-when-dark, +.theme-toggle svg.theme-icon-when-light { + fill: var(--header-link-color); + color: var(--header-bg); +} + +html[data-theme="auto"] .theme-toggle svg.theme-icon-when-auto { + display: block; +} + +html[data-theme="dark"] .theme-toggle svg.theme-icon-when-dark { + display: block; +} + +html[data-theme="light"] .theme-toggle svg.theme-icon-when-light { + display: block; +} + +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + overflow: hidden; + clip: rect(0,0,0,0); + white-space: nowrap; + border: 0; + color: var(--body-fg); + background-color: var(--body-bg); +} diff --git a/backend/week3/mydjangoproject/static/admin/css/dashboard.css b/backend/week3/mydjangoproject/static/admin/css/dashboard.css new file mode 100644 index 000000000..242b81a45 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/css/dashboard.css @@ -0,0 +1,29 @@ +/* DASHBOARD */ +.dashboard td, .dashboard th { + word-break: break-word; +} + +.dashboard .module table th { + width: 100%; +} + +.dashboard .module table td { + white-space: nowrap; +} + +.dashboard .module table td a { + display: block; + padding-right: .6em; +} + +/* RECENT ACTIONS MODULE */ + +.module ul.actionlist { + margin-left: 0; +} + +ul.actionlist li { + list-style-type: none; + overflow: hidden; + text-overflow: ellipsis; +} diff --git a/backend/week3/mydjangoproject/static/admin/css/forms.css b/backend/week3/mydjangoproject/static/admin/css/forms.css new file mode 100644 index 000000000..e45abe1c0 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/css/forms.css @@ -0,0 +1,530 @@ +@import url('widgets.css'); + +/* FORM ROWS */ + +.form-row { + overflow: hidden; + padding: 10px; + font-size: 0.8125rem; + border-bottom: 1px solid var(--hairline-color); +} + +.form-row img, .form-row input { + vertical-align: middle; +} + +.form-row label input[type="checkbox"] { + margin-top: 0; + vertical-align: 0; +} + +form .form-row p { + padding-left: 0; +} + +.flex-container { + display: flex; + flex-wrap: wrap; +} + +.form-multiline > div { + padding-bottom: 10px; +} + +/* FORM LABELS */ + +label { + font-weight: normal; + color: var(--body-quiet-color); + font-size: 0.8125rem; +} + +.required label, label.required { + font-weight: bold; + color: var(--body-fg); +} + +/* RADIO BUTTONS */ + +form div.radiolist div { + padding-right: 7px; +} + +form div.radiolist.inline div { + display: inline-block; +} + +form div.radiolist label { + width: auto; +} + +form div.radiolist input[type="radio"] { + margin: -2px 4px 0 0; + padding: 0; +} + +form ul.inline { + margin-left: 0; + padding: 0; +} + +form ul.inline li { + float: left; + padding-right: 7px; +} + +/* ALIGNED FIELDSETS */ + +.aligned label { + display: block; + padding: 4px 10px 0 0; + width: 160px; + word-wrap: break-word; + line-height: 1; +} + +.aligned label:not(.vCheckboxLabel):after { + content: ''; + display: inline-block; + vertical-align: middle; + height: 1.625rem; +} + +.aligned label + p, .aligned .checkbox-row + div.help, .aligned label + div.readonly { + padding: 6px 0; + margin-top: 0; + margin-bottom: 0; + margin-left: 0; + overflow-wrap: break-word; +} + +.aligned ul label { + display: inline; + float: none; + width: auto; +} + +.aligned .form-row input { + margin-bottom: 0; +} + +.colMS .aligned .vLargeTextField, .colMS .aligned .vXMLLargeTextField { + width: 350px; +} + +form .aligned ul { + margin-left: 160px; + padding-left: 10px; +} + +form .aligned div.radiolist { + display: inline-block; + margin: 0; + padding: 0; +} + +form .aligned p.help, +form .aligned div.help { + margin-top: 0; + margin-left: 160px; + padding-left: 10px; +} + +form .aligned p.date div.help.timezonewarning, +form .aligned p.datetime div.help.timezonewarning, +form .aligned p.time div.help.timezonewarning { + margin-left: 0; + padding-left: 0; + font-weight: normal; +} + +form .aligned p.help:last-child, +form .aligned div.help:last-child { + margin-bottom: 0; + padding-bottom: 0; +} + +form .aligned input + p.help, +form .aligned textarea + p.help, +form .aligned select + p.help, +form .aligned input + div.help, +form .aligned textarea + div.help, +form .aligned select + div.help { + margin-left: 160px; + padding-left: 10px; +} + +form .aligned ul li { + list-style: none; +} + +form .aligned table p { + margin-left: 0; + padding-left: 0; +} + +.aligned .vCheckboxLabel { + float: none; + width: auto; + display: inline-block; + vertical-align: -3px; + padding: 0 0 5px 5px; +} + +.aligned .vCheckboxLabel + p.help, +.aligned .vCheckboxLabel + div.help { + margin-top: -4px; +} + +.colM .aligned .vLargeTextField, .colM .aligned .vXMLLargeTextField { + width: 610px; +} + +fieldset .fieldBox { + margin-right: 20px; +} + +/* WIDE FIELDSETS */ + +.wide label { + width: 200px; +} + +form .wide p, +form .wide ul.errorlist, +form .wide input + p.help, +form .wide input + div.help { + margin-left: 200px; +} + +form .wide p.help, +form .wide div.help { + padding-left: 50px; +} + +form div.help ul { + padding-left: 0; + margin-left: 0; +} + +.colM fieldset.wide .vLargeTextField, .colM fieldset.wide .vXMLLargeTextField { + width: 450px; +} + +/* COLLAPSED FIELDSETS */ + +fieldset.collapsed * { + display: none; +} + +fieldset.collapsed h2, fieldset.collapsed { + display: block; +} + +fieldset.collapsed { + border: 1px solid var(--hairline-color); + border-radius: 4px; + overflow: hidden; +} + +fieldset.collapsed h2 { + background: var(--darkened-bg); + color: var(--body-quiet-color); +} + +fieldset .collapse-toggle { + color: var(--header-link-color); +} + +fieldset.collapsed .collapse-toggle { + background: transparent; + display: inline; + color: var(--link-fg); +} + +/* MONOSPACE TEXTAREAS */ + +fieldset.monospace textarea { + font-family: var(--font-family-monospace); +} + +/* SUBMIT ROW */ + +.submit-row { + padding: 12px 14px 12px; + margin: 0 0 20px; + background: var(--darkened-bg); + border: 1px solid var(--hairline-color); + border-radius: 4px; + overflow: hidden; + display: flex; + gap: 10px; + flex-wrap: wrap; +} + +body.popup .submit-row { + overflow: auto; +} + +.submit-row input { + height: 2.1875rem; + line-height: 0.9375rem; +} + +.submit-row input, .submit-row a { + margin: 0; +} + +.submit-row input.default { + text-transform: uppercase; +} + +.submit-row a.deletelink { + margin-left: auto; +} + +.submit-row a.deletelink { + display: block; + background: var(--delete-button-bg); + border-radius: 4px; + padding: 0.625rem 0.9375rem; + height: 0.9375rem; + line-height: 0.9375rem; + color: var(--button-fg); +} + +.submit-row a.closelink { + display: inline-block; + background: var(--close-button-bg); + border-radius: 4px; + padding: 10px 15px; + height: 0.9375rem; + line-height: 0.9375rem; + color: var(--button-fg); +} + +.submit-row a.deletelink:focus, +.submit-row a.deletelink:hover, +.submit-row a.deletelink:active { + background: var(--delete-button-hover-bg); + text-decoration: none; +} + +.submit-row a.closelink:focus, +.submit-row a.closelink:hover, +.submit-row a.closelink:active { + background: var(--close-button-hover-bg); + text-decoration: none; +} + +/* CUSTOM FORM FIELDS */ + +.vSelectMultipleField { + vertical-align: top; +} + +.vCheckboxField { + border: none; +} + +.vDateField, .vTimeField { + margin-right: 2px; + margin-bottom: 4px; +} + +.vDateField { + min-width: 6.85em; +} + +.vTimeField { + min-width: 4.7em; +} + +.vURLField { + width: 30em; +} + +.vLargeTextField, .vXMLLargeTextField { + width: 48em; +} + +.flatpages-flatpage #id_content { + height: 40.2em; +} + +.module table .vPositiveSmallIntegerField { + width: 2.2em; +} + +.vIntegerField { + width: 5em; +} + +.vBigIntegerField { + width: 10em; +} + +.vForeignKeyRawIdAdminField { + width: 5em; +} + +.vTextField, .vUUIDField { + width: 20em; +} + +/* INLINES */ + +.inline-group { + padding: 0; + margin: 0 0 30px; +} + +.inline-group thead th { + padding: 8px 10px; +} + +.inline-group .aligned label { + width: 160px; +} + +.inline-related { + position: relative; +} + +.inline-related h3 { + margin: 0; + color: var(--body-quiet-color); + padding: 5px; + font-size: 0.8125rem; + background: var(--darkened-bg); + border-top: 1px solid var(--hairline-color); + border-bottom: 1px solid var(--hairline-color); +} + +.inline-related h3 span.delete { + float: right; +} + +.inline-related h3 span.delete label { + margin-left: 2px; + font-size: 0.6875rem; +} + +.inline-related fieldset { + margin: 0; + background: var(--body-bg); + border: none; + width: 100%; +} + +.inline-related fieldset.module h3 { + margin: 0; + padding: 2px 5px 3px 5px; + font-size: 0.6875rem; + text-align: left; + font-weight: bold; + background: #bcd; + color: var(--body-bg); +} + +.inline-group .tabular fieldset.module { + border: none; +} + +.inline-related.tabular fieldset.module table { + width: 100%; + overflow-x: scroll; +} + +.last-related fieldset { + border: none; +} + +.inline-group .tabular tr.has_original td { + padding-top: 2em; +} + +.inline-group .tabular tr td.original { + padding: 2px 0 0 0; + width: 0; + _position: relative; +} + +.inline-group .tabular th.original { + width: 0px; + padding: 0; +} + +.inline-group .tabular td.original p { + position: absolute; + left: 0; + height: 1.1em; + padding: 2px 9px; + overflow: hidden; + font-size: 0.5625rem; + font-weight: bold; + color: var(--body-quiet-color); + _width: 700px; +} + +.inline-group ul.tools { + padding: 0; + margin: 0; + list-style: none; +} + +.inline-group ul.tools li { + display: inline; + padding: 0 5px; +} + +.inline-group div.add-row, +.inline-group .tabular tr.add-row td { + color: var(--body-quiet-color); + background: var(--darkened-bg); + padding: 8px 10px; + border-bottom: 1px solid var(--hairline-color); +} + +.inline-group .tabular tr.add-row td { + padding: 8px 10px; + border-bottom: 1px solid var(--hairline-color); +} + +.inline-group ul.tools a.add, +.inline-group div.add-row a, +.inline-group .tabular tr.add-row td a { + background: url(../img/icon-addlink.svg) 0 1px no-repeat; + padding-left: 16px; + font-size: 0.75rem; +} + +.empty-form { + display: none; +} + +/* RELATED FIELD ADD ONE / LOOKUP */ + +.related-lookup { + margin-left: 5px; + display: inline-block; + vertical-align: middle; + background-repeat: no-repeat; + background-size: 14px; +} + +.related-lookup { + width: 1rem; + height: 1rem; + background-image: url(../img/search.svg); +} + +form .related-widget-wrapper ul { + display: inline-block; + margin-left: 0; + padding-left: 0; +} + +.clearable-file-input input { + margin-top: 0; +} diff --git a/backend/week3/mydjangoproject/static/admin/css/login.css b/backend/week3/mydjangoproject/static/admin/css/login.css new file mode 100644 index 000000000..389772f5b --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/css/login.css @@ -0,0 +1,61 @@ +/* LOGIN FORM */ + +.login { + background: var(--darkened-bg); + height: auto; +} + +.login #header { + height: auto; + padding: 15px 16px; + justify-content: center; +} + +.login #header h1 { + font-size: 1.125rem; + margin: 0; +} + +.login #header h1 a { + color: var(--header-link-color); +} + +.login #content { + padding: 20px 20px 0; +} + +.login #container { + background: var(--body-bg); + border: 1px solid var(--hairline-color); + border-radius: 4px; + overflow: hidden; + width: 28em; + min-width: 300px; + margin: 100px auto; + height: auto; +} + +.login .form-row { + padding: 4px 0; +} + +.login .form-row label { + display: block; + line-height: 2em; +} + +.login .form-row #id_username, .login .form-row #id_password { + padding: 8px; + width: 100%; + box-sizing: border-box; +} + +.login .submit-row { + padding: 1em 0 0 0; + margin: 0; + text-align: center; +} + +.login .password-reset-link { + text-align: center; +} diff --git a/backend/week3/mydjangoproject/static/admin/css/nav_sidebar.css b/backend/week3/mydjangoproject/static/admin/css/nav_sidebar.css new file mode 100644 index 000000000..f76e6ce48 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/css/nav_sidebar.css @@ -0,0 +1,144 @@ +.sticky { + position: sticky; + top: 0; + max-height: 100vh; +} + +.toggle-nav-sidebar { + z-index: 20; + left: 0; + display: flex; + align-items: center; + justify-content: center; + flex: 0 0 23px; + width: 23px; + border: 0; + border-right: 1px solid var(--hairline-color); + background-color: var(--body-bg); + cursor: pointer; + font-size: 1.25rem; + color: var(--link-fg); + padding: 0; +} + +[dir="rtl"] .toggle-nav-sidebar { + border-left: 1px solid var(--hairline-color); + border-right: 0; +} + +.toggle-nav-sidebar:hover, +.toggle-nav-sidebar:focus { + background-color: var(--darkened-bg); +} + +#nav-sidebar { + z-index: 15; + flex: 0 0 275px; + left: -276px; + margin-left: -276px; + border-top: 1px solid transparent; + border-right: 1px solid var(--hairline-color); + background-color: var(--body-bg); + overflow: auto; +} + +[dir="rtl"] #nav-sidebar { + border-left: 1px solid var(--hairline-color); + border-right: 0; + left: 0; + margin-left: 0; + right: -276px; + margin-right: -276px; +} + +.toggle-nav-sidebar::before { + content: '\00BB'; +} + +.main.shifted .toggle-nav-sidebar::before { + content: '\00AB'; +} + +.main > #nav-sidebar { + visibility: hidden; +} + +.main.shifted > #nav-sidebar { + margin-left: 0; + visibility: visible; +} + +[dir="rtl"] .main.shifted > #nav-sidebar { + margin-right: 0; +} + +#nav-sidebar .module th { + width: 100%; + overflow-wrap: anywhere; +} + +#nav-sidebar .module th, +#nav-sidebar .module caption { + padding-left: 16px; +} + +#nav-sidebar .module td { + white-space: nowrap; +} + +[dir="rtl"] #nav-sidebar .module th, +[dir="rtl"] #nav-sidebar .module caption { + padding-left: 8px; + padding-right: 16px; +} + +#nav-sidebar .current-app .section:link, +#nav-sidebar .current-app .section:visited { + color: var(--header-color); + font-weight: bold; +} + +#nav-sidebar .current-model { + background: var(--selected-row); +} + +.main > #nav-sidebar + .content { + max-width: calc(100% - 23px); +} + +.main.shifted > #nav-sidebar + .content { + max-width: calc(100% - 299px); +} + +@media (max-width: 767px) { + #nav-sidebar, #toggle-nav-sidebar { + display: none; + } + + .main > #nav-sidebar + .content, + .main.shifted > #nav-sidebar + .content { + max-width: 100%; + } +} + +#nav-filter { + width: 100%; + box-sizing: border-box; + padding: 2px 5px; + margin: 5px 0; + border: 1px solid var(--border-color); + background-color: var(--darkened-bg); + color: var(--body-fg); +} + +#nav-filter:focus { + border-color: var(--body-quiet-color); +} + +#nav-filter.no-results { + background: var(--message-error-bg); +} + +#nav-sidebar table { + width: 100%; +} diff --git a/backend/week3/mydjangoproject/static/admin/css/responsive.css b/backend/week3/mydjangoproject/static/admin/css/responsive.css new file mode 100644 index 000000000..9ce4f67bf --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/css/responsive.css @@ -0,0 +1,998 @@ +/* Tablets */ + +input[type="submit"], button { + -webkit-appearance: none; + appearance: none; +} + +@media (max-width: 1024px) { + /* Basic */ + + html { + -webkit-text-size-adjust: 100%; + } + + td, th { + padding: 10px; + font-size: 0.875rem; + } + + .small { + font-size: 0.75rem; + } + + /* Layout */ + + #container { + min-width: 0; + } + + #content { + padding: 15px 20px 20px; + } + + div.breadcrumbs { + padding: 10px 30px; + } + + /* Header */ + + #header { + flex-direction: column; + padding: 15px 30px; + justify-content: flex-start; + } + + #branding h1 { + margin: 0 0 8px; + line-height: 1.2; + } + + #user-tools { + margin: 0; + font-weight: 400; + line-height: 1.85; + text-align: left; + } + + #user-tools a { + display: inline-block; + line-height: 1.4; + } + + /* Dashboard */ + + .dashboard #content { + width: auto; + } + + #content-related { + margin-right: -290px; + } + + .colSM #content-related { + margin-left: -290px; + } + + .colMS { + margin-right: 290px; + } + + .colSM { + margin-left: 290px; + } + + .dashboard .module table td a { + padding-right: 0; + } + + td .changelink, td .addlink { + font-size: 0.8125rem; + } + + /* Changelist */ + + #toolbar { + border: none; + padding: 15px; + } + + #changelist-search > div { + display: flex; + flex-wrap: nowrap; + max-width: 480px; + } + + #changelist-search label { + line-height: 1.375rem; + } + + #toolbar form #searchbar { + flex: 1 0 auto; + width: 0; + height: 1.375rem; + margin: 0 10px 0 6px; + } + + #toolbar form input[type=submit] { + flex: 0 1 auto; + } + + #changelist-search .quiet { + width: 0; + flex: 1 0 auto; + margin: 5px 0 0 25px; + } + + #changelist .actions { + display: flex; + flex-wrap: wrap; + padding: 15px 0; + } + + #changelist .actions label { + display: flex; + } + + #changelist .actions select { + background: var(--body-bg); + } + + #changelist .actions .button { + min-width: 48px; + margin: 0 10px; + } + + #changelist .actions span.all, + #changelist .actions span.clear, + #changelist .actions span.question, + #changelist .actions span.action-counter { + font-size: 0.6875rem; + margin: 0 10px 0 0; + } + + #changelist-filter { + flex-basis: 200px; + } + + .change-list .filtered .results, + .change-list .filtered .paginator, + .filtered #toolbar, + .filtered .actions, + + #changelist .paginator { + border-top-color: var(--hairline-color); /* XXX Is this used at all? */ + } + + #changelist .results + .paginator { + border-top: none; + } + + /* Forms */ + + label { + font-size: 0.875rem; + } + + .form-row input[type=text], + .form-row input[type=password], + .form-row input[type=email], + .form-row input[type=url], + .form-row input[type=tel], + .form-row input[type=number], + .form-row textarea, + .form-row select, + .form-row .vTextField { + box-sizing: border-box; + margin: 0; + padding: 6px 8px; + min-height: 2.25rem; + font-size: 0.875rem; + } + + .form-row select { + height: 2.25rem; + } + + .form-row select[multiple] { + height: auto; + min-height: 0; + } + + fieldset .fieldBox + .fieldBox { + margin-top: 10px; + padding-top: 10px; + border-top: 1px solid var(--hairline-color); + } + + textarea { + max-width: 100%; + max-height: 120px; + } + + .aligned label { + padding-top: 6px; + } + + .aligned .related-lookup, + .aligned .datetimeshortcuts, + .aligned .related-lookup + strong { + align-self: center; + margin-left: 15px; + } + + form .aligned div.radiolist { + margin-left: 2px; + } + + .submit-row { + padding: 8px; + } + + .submit-row a.deletelink { + padding: 10px 7px; + } + + .button, input[type=submit], input[type=button], .submit-row input, a.button { + padding: 7px; + } + + /* Related widget */ + + .related-widget-wrapper { + float: none; + } + + .related-widget-wrapper-link + .selector { + max-width: calc(100% - 30px); + margin-right: 15px; + } + + select + .related-widget-wrapper-link, + .related-widget-wrapper-link + .related-widget-wrapper-link { + margin-left: 10px; + } + + /* Selector */ + + .selector { + display: flex; + width: 100%; + } + + .selector .selector-filter { + display: flex; + align-items: center; + } + + .selector .selector-filter label { + margin: 0 8px 0 0; + } + + .selector .selector-filter input { + width: auto; + min-height: 0; + flex: 1 1; + } + + .selector-available, .selector-chosen { + width: auto; + flex: 1 1; + display: flex; + flex-direction: column; + } + + .selector select { + width: 100%; + flex: 1 0 auto; + margin-bottom: 5px; + } + + .selector ul.selector-chooser { + width: 26px; + height: 52px; + padding: 2px 0; + margin: auto 15px; + border-radius: 20px; + transform: translateY(-10px); + } + + .selector-add, .selector-remove { + width: 20px; + height: 20px; + background-size: 20px auto; + } + + .selector-add { + background-position: 0 -120px; + } + + .selector-remove { + background-position: 0 -80px; + } + + a.selector-chooseall, a.selector-clearall { + align-self: center; + } + + .stacked { + flex-direction: column; + max-width: 480px; + } + + .stacked > * { + flex: 0 1 auto; + } + + .stacked select { + margin-bottom: 0; + } + + .stacked .selector-available, .stacked .selector-chosen { + width: auto; + } + + .stacked ul.selector-chooser { + width: 52px; + height: 26px; + padding: 0 2px; + margin: 15px auto; + transform: none; + } + + .stacked .selector-chooser li { + padding: 3px; + } + + .stacked .selector-add, .stacked .selector-remove { + background-size: 20px auto; + } + + .stacked .selector-add { + background-position: 0 -40px; + } + + .stacked .active.selector-add { + background-position: 0 -40px; + } + + .active.selector-add:focus, .active.selector-add:hover { + background-position: 0 -140px; + } + + .stacked .active.selector-add:focus, .stacked .active.selector-add:hover { + background-position: 0 -60px; + } + + .stacked .selector-remove { + background-position: 0 0; + } + + .stacked .active.selector-remove { + background-position: 0 0; + } + + .active.selector-remove:focus, .active.selector-remove:hover { + background-position: 0 -100px; + } + + .stacked .active.selector-remove:focus, .stacked .active.selector-remove:hover { + background-position: 0 -20px; + } + + .help-tooltip, .selector .help-icon { + display: none; + } + + .datetime input { + width: 50%; + max-width: 120px; + } + + .datetime span { + font-size: 0.8125rem; + } + + .datetime .timezonewarning { + display: block; + font-size: 0.6875rem; + color: var(--body-quiet-color); + } + + .datetimeshortcuts { + color: var(--border-color); /* XXX Redundant, .datetime span also sets #ccc */ + } + + .form-row .datetime input.vDateField, .form-row .datetime input.vTimeField { + width: 75%; + } + + .inline-group { + overflow: auto; + } + + /* Messages */ + + ul.messagelist li { + padding-left: 55px; + background-position: 30px 12px; + } + + ul.messagelist li.error { + background-position: 30px 12px; + } + + ul.messagelist li.warning { + background-position: 30px 14px; + } + + /* Login */ + + .login #header { + padding: 15px 20px; + } + + .login #branding h1 { + margin: 0; + } + + /* GIS */ + + div.olMap { + max-width: calc(100vw - 30px); + max-height: 300px; + } + + .olMap + .clear_features { + display: block; + margin-top: 10px; + } + + /* Docs */ + + .module table.xfull { + width: 100%; + } + + pre.literal-block { + overflow: auto; + } +} + +/* Mobile */ + +@media (max-width: 767px) { + /* Layout */ + + #header, #content, #footer { + padding: 15px; + } + + #footer:empty { + padding: 0; + } + + div.breadcrumbs { + padding: 10px 15px; + } + + /* Dashboard */ + + .colMS, .colSM { + margin: 0; + } + + #content-related, .colSM #content-related { + width: 100%; + margin: 0; + } + + #content-related .module { + margin-bottom: 0; + } + + #content-related .module h2 { + padding: 10px 15px; + font-size: 1rem; + } + + /* Changelist */ + + #changelist { + align-items: stretch; + flex-direction: column; + } + + #toolbar { + padding: 10px; + } + + #changelist-filter { + margin-left: 0; + } + + #changelist .actions label { + flex: 1 1; + } + + #changelist .actions select { + flex: 1 0; + width: 100%; + } + + #changelist .actions span { + flex: 1 0 100%; + } + + #changelist-filter { + position: static; + width: auto; + margin-top: 30px; + } + + .object-tools { + float: none; + margin: 0 0 15px; + padding: 0; + overflow: hidden; + } + + .object-tools li { + height: auto; + margin-left: 0; + } + + .object-tools li + li { + margin-left: 15px; + } + + /* Forms */ + + .form-row { + padding: 15px 0; + } + + .aligned .form-row, + .aligned .form-row > div { + max-width: 100vw; + } + + .aligned .form-row > div { + width: calc(100vw - 30px); + } + + .flex-container { + flex-flow: column; + } + + textarea { + max-width: none; + } + + .vURLField { + width: auto; + } + + fieldset .fieldBox + .fieldBox { + margin-top: 15px; + padding-top: 15px; + } + + fieldset.collapsed .form-row { + display: none; + } + + .aligned label { + width: 100%; + padding: 0 0 10px; + } + + .aligned label:after { + max-height: 0; + } + + .aligned .form-row input, + .aligned .form-row select, + .aligned .form-row textarea { + flex: 1 1 auto; + max-width: 100%; + } + + .aligned .checkbox-row { + align-items: center; + } + + .aligned .checkbox-row input { + flex: 0 1 auto; + margin: 0; + } + + .aligned .vCheckboxLabel { + flex: 1 0; + padding: 1px 0 0 5px; + } + + .aligned label + p, + .aligned label + div.help, + .aligned label + div.readonly { + padding: 0; + margin-left: 0; + } + + .aligned p.file-upload { + font-size: 0.8125rem; + } + + span.clearable-file-input { + margin-left: 15px; + } + + span.clearable-file-input label { + font-size: 0.8125rem; + padding-bottom: 0; + } + + .aligned .timezonewarning { + flex: 1 0 100%; + margin-top: 5px; + } + + form .aligned .form-row div.help { + width: 100%; + margin: 5px 0 0; + padding: 0; + } + + form .aligned ul, + form .aligned ul.errorlist { + margin-left: 0; + padding-left: 0; + } + + form .aligned div.radiolist { + margin-top: 5px; + margin-right: 15px; + margin-bottom: -3px; + } + + form .aligned div.radiolist:not(.inline) div + div { + margin-top: 5px; + } + + /* Related widget */ + + .related-widget-wrapper { + width: 100%; + display: flex; + align-items: flex-start; + } + + .related-widget-wrapper .selector { + order: 1; + } + + .related-widget-wrapper > a { + order: 2; + } + + .related-widget-wrapper .radiolist ~ a { + align-self: flex-end; + } + + .related-widget-wrapper > select ~ a { + align-self: center; + } + + select + .related-widget-wrapper-link, + .related-widget-wrapper-link + .related-widget-wrapper-link { + margin-left: 15px; + } + + /* Selector */ + + .selector { + flex-direction: column; + } + + .selector > * { + float: none; + } + + .selector-available, .selector-chosen { + margin-bottom: 0; + flex: 1 1 auto; + } + + .selector select { + max-height: 96px; + } + + .selector ul.selector-chooser { + display: block; + float: none; + width: 52px; + height: 26px; + padding: 0 2px; + margin: 15px auto 20px; + transform: none; + } + + .selector ul.selector-chooser li { + float: left; + } + + .selector-remove { + background-position: 0 0; + } + + .active.selector-remove:focus, .active.selector-remove:hover { + background-position: 0 -20px; + } + + .selector-add { + background-position: 0 -40px; + } + + .active.selector-add:focus, .active.selector-add:hover { + background-position: 0 -60px; + } + + /* Inlines */ + + .inline-group[data-inline-type="stacked"] .inline-related { + border: 1px solid var(--hairline-color); + border-radius: 4px; + margin-top: 15px; + overflow: auto; + } + + .inline-group[data-inline-type="stacked"] .inline-related > * { + box-sizing: border-box; + } + + .inline-group[data-inline-type="stacked"] .inline-related .module { + padding: 0 10px; + } + + .inline-group[data-inline-type="stacked"] .inline-related .module .form-row { + border-top: 1px solid var(--hairline-color); + border-bottom: none; + } + + .inline-group[data-inline-type="stacked"] .inline-related .module .form-row:first-child { + border-top: none; + } + + .inline-group[data-inline-type="stacked"] .inline-related h3 { + padding: 10px; + border-top-width: 0; + border-bottom-width: 2px; + display: flex; + flex-wrap: wrap; + align-items: center; + } + + .inline-group[data-inline-type="stacked"] .inline-related h3 .inline_label { + margin-right: auto; + } + + .inline-group[data-inline-type="stacked"] .inline-related h3 span.delete { + float: none; + flex: 1 1 100%; + margin-top: 5px; + } + + .inline-group[data-inline-type="stacked"] .aligned .form-row > div:not([class]) { + width: 100%; + } + + .inline-group[data-inline-type="stacked"] .aligned label { + width: 100%; + } + + .inline-group[data-inline-type="stacked"] div.add-row { + margin-top: 15px; + border: 1px solid var(--hairline-color); + border-radius: 4px; + } + + .inline-group div.add-row, + .inline-group .tabular tr.add-row td { + padding: 0; + } + + .inline-group div.add-row a, + .inline-group .tabular tr.add-row td a { + display: block; + padding: 8px 10px 8px 26px; + background-position: 8px 9px; + } + + /* Submit row */ + + .submit-row { + padding: 10px; + margin: 0 0 15px; + flex-direction: column; + gap: 8px; + } + + .submit-row input, .submit-row input.default, .submit-row a { + text-align: center; + } + + .submit-row a.closelink { + padding: 10px 0; + text-align: center; + } + + .submit-row a.deletelink { + margin: 0; + } + + /* Messages */ + + ul.messagelist li { + padding-left: 40px; + background-position: 15px 12px; + } + + ul.messagelist li.error { + background-position: 15px 12px; + } + + ul.messagelist li.warning { + background-position: 15px 14px; + } + + /* Paginator */ + + .paginator .this-page, .paginator a:link, .paginator a:visited { + padding: 4px 10px; + } + + /* Login */ + + body.login { + padding: 0 15px; + } + + .login #container { + width: auto; + max-width: 480px; + margin: 50px auto; + } + + .login #header, + .login #content { + padding: 15px; + } + + .login #content-main { + float: none; + } + + .login .form-row { + padding: 0; + } + + .login .form-row + .form-row { + margin-top: 15px; + } + + .login .form-row label { + margin: 0 0 5px; + line-height: 1.2; + } + + .login .submit-row { + padding: 15px 0 0; + } + + .login br { + display: none; + } + + .login .submit-row input { + margin: 0; + text-transform: uppercase; + } + + .errornote { + margin: 0 0 20px; + padding: 8px 12px; + font-size: 0.8125rem; + } + + /* Calendar and clock */ + + .calendarbox, .clockbox { + position: fixed !important; + top: 50% !important; + left: 50% !important; + transform: translate(-50%, -50%); + margin: 0; + border: none; + overflow: visible; + } + + .calendarbox:before, .clockbox:before { + content: ''; + position: fixed; + top: 50%; + left: 50%; + width: 100vw; + height: 100vh; + background: rgba(0, 0, 0, 0.75); + transform: translate(-50%, -50%); + } + + .calendarbox > *, .clockbox > * { + position: relative; + z-index: 1; + } + + .calendarbox > div:first-child { + z-index: 2; + } + + .calendarbox .calendar, .clockbox h2 { + border-radius: 4px 4px 0 0; + overflow: hidden; + } + + .calendarbox .calendar-cancel, .clockbox .calendar-cancel { + border-radius: 0 0 4px 4px; + overflow: hidden; + } + + .calendar-shortcuts { + padding: 10px 0; + font-size: 0.75rem; + line-height: 0.75rem; + } + + .calendar-shortcuts a { + margin: 0 4px; + } + + .timelist a { + background: var(--body-bg); + padding: 4px; + } + + .calendar-cancel { + padding: 8px 10px; + } + + .clockbox h2 { + padding: 8px 15px; + } + + .calendar caption { + padding: 10px; + } + + .calendarbox .calendarnav-previous, .calendarbox .calendarnav-next { + z-index: 1; + top: 10px; + } + + /* History */ + + table#change-history tbody th, table#change-history tbody td { + font-size: 0.8125rem; + word-break: break-word; + } + + table#change-history tbody th { + width: auto; + } + + /* Docs */ + + table.model tbody th, table.model tbody td { + font-size: 0.8125rem; + word-break: break-word; + } +} diff --git a/backend/week3/mydjangoproject/static/admin/css/responsive_rtl.css b/backend/week3/mydjangoproject/static/admin/css/responsive_rtl.css new file mode 100644 index 000000000..639e20b2d --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/css/responsive_rtl.css @@ -0,0 +1,81 @@ +/* TABLETS */ + +@media (max-width: 1024px) { + [dir="rtl"] .colMS { + margin-right: 0; + } + + [dir="rtl"] #user-tools { + text-align: right; + } + + [dir="rtl"] #changelist .actions label { + padding-left: 10px; + padding-right: 0; + } + + [dir="rtl"] #changelist .actions select { + margin-left: 0; + margin-right: 15px; + } + + [dir="rtl"] .change-list .filtered .results, + [dir="rtl"] .change-list .filtered .paginator, + [dir="rtl"] .filtered #toolbar, + [dir="rtl"] .filtered div.xfull, + [dir="rtl"] .filtered .actions, + [dir="rtl"] #changelist-filter { + margin-left: 0; + } + + [dir="rtl"] .inline-group ul.tools a.add, + [dir="rtl"] .inline-group div.add-row a, + [dir="rtl"] .inline-group .tabular tr.add-row td a { + padding: 8px 26px 8px 10px; + background-position: calc(100% - 8px) 9px; + } + + [dir="rtl"] .related-widget-wrapper-link + .selector { + margin-right: 0; + margin-left: 15px; + } + + [dir="rtl"] .selector .selector-filter label { + margin-right: 0; + margin-left: 8px; + } + + [dir="rtl"] .object-tools li { + float: right; + } + + [dir="rtl"] .object-tools li + li { + margin-left: 0; + margin-right: 15px; + } + + [dir="rtl"] .dashboard .module table td a { + padding-left: 0; + padding-right: 16px; + } +} + +/* MOBILE */ + +@media (max-width: 767px) { + [dir="rtl"] .aligned .related-lookup, + [dir="rtl"] .aligned .datetimeshortcuts { + margin-left: 0; + margin-right: 15px; + } + + [dir="rtl"] .aligned ul, + [dir="rtl"] form .aligned ul.errorlist { + margin-right: 0; + } + + [dir="rtl"] #changelist-filter { + margin-left: 0; + margin-right: 0; + } +} diff --git a/backend/week3/mydjangoproject/static/admin/css/rtl.css b/backend/week3/mydjangoproject/static/admin/css/rtl.css new file mode 100644 index 000000000..53a6dd6ca --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/css/rtl.css @@ -0,0 +1,288 @@ +/* GLOBAL */ + +th { + text-align: right; +} + +.module h2, .module caption { + text-align: right; +} + +.module ul, .module ol { + margin-left: 0; + margin-right: 1.5em; +} + +.viewlink, .addlink, .changelink { + padding-left: 0; + padding-right: 16px; + background-position: 100% 1px; +} + +.deletelink { + padding-left: 0; + padding-right: 16px; + background-position: 100% 1px; +} + +.object-tools { + float: left; +} + +thead th:first-child, +tfoot td:first-child { + border-left: none; +} + +/* LAYOUT */ + +#user-tools { + right: auto; + left: 0; + text-align: left; +} + +div.breadcrumbs { + text-align: right; +} + +#content-main { + float: right; +} + +#content-related { + float: left; + margin-left: -300px; + margin-right: auto; +} + +.colMS { + margin-left: 300px; + margin-right: 0; +} + +/* SORTABLE TABLES */ + +table thead th.sorted .sortoptions { + float: left; +} + +thead th.sorted .text { + padding-right: 0; + padding-left: 42px; +} + +/* dashboard styles */ + +.dashboard .module table td a { + padding-left: .6em; + padding-right: 16px; +} + +/* changelists styles */ + +.change-list .filtered table { + border-left: none; + border-right: 0px none; +} + +#changelist-filter { + border-left: none; + border-right: none; + margin-left: 0; + margin-right: 30px; +} + +#changelist-filter li.selected { + border-left: none; + padding-left: 10px; + margin-left: 0; + border-right: 5px solid var(--hairline-color); + padding-right: 10px; + margin-right: -15px; +} + +#changelist table tbody td:first-child, #changelist table tbody th:first-child { + border-right: none; + border-left: none; +} + +/* FORMS */ + +.aligned label { + padding: 0 0 3px 1em; +} + +.submit-row a.deletelink { + margin-left: 0; + margin-right: auto; +} + +.vDateField, .vTimeField { + margin-left: 2px; +} + +.aligned .form-row input { + margin-left: 5px; +} + +form .aligned ul { + margin-right: 163px; + padding-right: 10px; + margin-left: 0; + padding-left: 0; +} + +form ul.inline li { + float: right; + padding-right: 0; + padding-left: 7px; +} + +form .aligned p.help, +form .aligned div.help { + margin-right: 160px; + padding-right: 10px; +} + +form div.help ul, +form .aligned .checkbox-row + .help, +form .aligned p.date div.help.timezonewarning, +form .aligned p.datetime div.help.timezonewarning, +form .aligned p.time div.help.timezonewarning { + margin-right: 0; + padding-right: 0; +} + +form .wide p.help, form .wide div.help { + padding-left: 0; + padding-right: 50px; +} + +form .wide p, +form .wide ul.errorlist, +form .wide input + p.help, +form .wide input + div.help { + margin-right: 200px; + margin-left: 0px; +} + +.submit-row { + text-align: right; +} + +fieldset .fieldBox { + margin-left: 20px; + margin-right: 0; +} + +.errorlist li { + background-position: 100% 12px; + padding: 0; +} + +.errornote { + background-position: 100% 12px; + padding: 10px 12px; +} + +/* WIDGETS */ + +.calendarnav-previous { + top: 0; + left: auto; + right: 10px; + background: url(../img/calendar-icons.svg) 0 -30px no-repeat; +} + +.calendarbox .calendarnav-previous:focus, +.calendarbox .calendarnav-previous:hover { + background-position: 0 -45px; +} + +.calendarnav-next { + top: 0; + right: auto; + left: 10px; + background: url(../img/calendar-icons.svg) 0 0 no-repeat; +} + +.calendarbox .calendarnav-next:focus, +.calendarbox .calendarnav-next:hover { + background-position: 0 -15px; +} + +.calendar caption, .calendarbox h2 { + text-align: center; +} + +.selector { + float: right; +} + +.selector .selector-filter { + text-align: right; +} + +.selector-add { + background: url(../img/selector-icons.svg) 0 -64px no-repeat; +} + +.active.selector-add:focus, .active.selector-add:hover { + background-position: 0 -80px; +} + +.selector-remove { + background: url(../img/selector-icons.svg) 0 -96px no-repeat; +} + +.active.selector-remove:focus, .active.selector-remove:hover { + background-position: 0 -112px; +} + +a.selector-chooseall { + background: url(../img/selector-icons.svg) right -128px no-repeat; +} + +a.active.selector-chooseall:focus, a.active.selector-chooseall:hover { + background-position: 100% -144px; +} + +a.selector-clearall { + background: url(../img/selector-icons.svg) 0 -160px no-repeat; +} + +a.active.selector-clearall:focus, a.active.selector-clearall:hover { + background-position: 0 -176px; +} + +.inline-deletelink { + float: left; +} + +form .form-row p.datetime { + overflow: hidden; +} + +.related-widget-wrapper { + float: right; +} + +/* MISC */ + +.inline-related h2, .inline-group h2 { + text-align: right +} + +.inline-related h3 span.delete { + padding-right: 20px; + padding-left: inherit; + left: 10px; + right: inherit; + float:left; +} + +.inline-related h3 span.delete label { + margin-left: inherit; + margin-right: 2px; +} diff --git a/backend/week3/mydjangoproject/static/admin/css/vendor/select2/LICENSE-SELECT2.md b/backend/week3/mydjangoproject/static/admin/css/vendor/select2/LICENSE-SELECT2.md new file mode 100644 index 000000000..8cb8a2b12 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/css/vendor/select2/LICENSE-SELECT2.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2012-2017 Kevin Brown, Igor Vaynberg, and Select2 contributors + +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. diff --git a/backend/week3/mydjangoproject/static/admin/css/vendor/select2/select2.css b/backend/week3/mydjangoproject/static/admin/css/vendor/select2/select2.css new file mode 100644 index 000000000..750b3207a --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/css/vendor/select2/select2.css @@ -0,0 +1,481 @@ +.select2-container { + box-sizing: border-box; + display: inline-block; + margin: 0; + position: relative; + vertical-align: middle; } + .select2-container .select2-selection--single { + box-sizing: border-box; + cursor: pointer; + display: block; + height: 28px; + user-select: none; + -webkit-user-select: none; } + .select2-container .select2-selection--single .select2-selection__rendered { + display: block; + padding-left: 8px; + padding-right: 20px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } + .select2-container .select2-selection--single .select2-selection__clear { + position: relative; } + .select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered { + padding-right: 8px; + padding-left: 20px; } + .select2-container .select2-selection--multiple { + box-sizing: border-box; + cursor: pointer; + display: block; + min-height: 32px; + user-select: none; + -webkit-user-select: none; } + .select2-container .select2-selection--multiple .select2-selection__rendered { + display: inline-block; + overflow: hidden; + padding-left: 8px; + text-overflow: ellipsis; + white-space: nowrap; } + .select2-container .select2-search--inline { + float: left; } + .select2-container .select2-search--inline .select2-search__field { + box-sizing: border-box; + border: none; + font-size: 100%; + margin-top: 5px; + padding: 0; } + .select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button { + -webkit-appearance: none; } + +.select2-dropdown { + background-color: white; + border: 1px solid #aaa; + border-radius: 4px; + box-sizing: border-box; + display: block; + position: absolute; + left: -100000px; + width: 100%; + z-index: 1051; } + +.select2-results { + display: block; } + +.select2-results__options { + list-style: none; + margin: 0; + padding: 0; } + +.select2-results__option { + padding: 6px; + user-select: none; + -webkit-user-select: none; } + .select2-results__option[aria-selected] { + cursor: pointer; } + +.select2-container--open .select2-dropdown { + left: 0; } + +.select2-container--open .select2-dropdown--above { + border-bottom: none; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; } + +.select2-container--open .select2-dropdown--below { + border-top: none; + border-top-left-radius: 0; + border-top-right-radius: 0; } + +.select2-search--dropdown { + display: block; + padding: 4px; } + .select2-search--dropdown .select2-search__field { + padding: 4px; + width: 100%; + box-sizing: border-box; } + .select2-search--dropdown .select2-search__field::-webkit-search-cancel-button { + -webkit-appearance: none; } + .select2-search--dropdown.select2-search--hide { + display: none; } + +.select2-close-mask { + border: 0; + margin: 0; + padding: 0; + display: block; + position: fixed; + left: 0; + top: 0; + min-height: 100%; + min-width: 100%; + height: auto; + width: auto; + opacity: 0; + z-index: 99; + background-color: #fff; + filter: alpha(opacity=0); } + +.select2-hidden-accessible { + border: 0 !important; + clip: rect(0 0 0 0) !important; + -webkit-clip-path: inset(50%) !important; + clip-path: inset(50%) !important; + height: 1px !important; + overflow: hidden !important; + padding: 0 !important; + position: absolute !important; + width: 1px !important; + white-space: nowrap !important; } + +.select2-container--default .select2-selection--single { + background-color: #fff; + border: 1px solid #aaa; + border-radius: 4px; } + .select2-container--default .select2-selection--single .select2-selection__rendered { + color: #444; + line-height: 28px; } + .select2-container--default .select2-selection--single .select2-selection__clear { + cursor: pointer; + float: right; + font-weight: bold; } + .select2-container--default .select2-selection--single .select2-selection__placeholder { + color: #999; } + .select2-container--default .select2-selection--single .select2-selection__arrow { + height: 26px; + position: absolute; + top: 1px; + right: 1px; + width: 20px; } + .select2-container--default .select2-selection--single .select2-selection__arrow b { + border-color: #888 transparent transparent transparent; + border-style: solid; + border-width: 5px 4px 0 4px; + height: 0; + left: 50%; + margin-left: -4px; + margin-top: -2px; + position: absolute; + top: 50%; + width: 0; } + +.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear { + float: left; } + +.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow { + left: 1px; + right: auto; } + +.select2-container--default.select2-container--disabled .select2-selection--single { + background-color: #eee; + cursor: default; } + .select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear { + display: none; } + +.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b { + border-color: transparent transparent #888 transparent; + border-width: 0 4px 5px 4px; } + +.select2-container--default .select2-selection--multiple { + background-color: white; + border: 1px solid #aaa; + border-radius: 4px; + cursor: text; } + .select2-container--default .select2-selection--multiple .select2-selection__rendered { + box-sizing: border-box; + list-style: none; + margin: 0; + padding: 0 5px; + width: 100%; } + .select2-container--default .select2-selection--multiple .select2-selection__rendered li { + list-style: none; } + .select2-container--default .select2-selection--multiple .select2-selection__clear { + cursor: pointer; + float: right; + font-weight: bold; + margin-top: 5px; + margin-right: 10px; + padding: 1px; } + .select2-container--default .select2-selection--multiple .select2-selection__choice { + background-color: #e4e4e4; + border: 1px solid #aaa; + border-radius: 4px; + cursor: default; + float: left; + margin-right: 5px; + margin-top: 5px; + padding: 0 5px; } + .select2-container--default .select2-selection--multiple .select2-selection__choice__remove { + color: #999; + cursor: pointer; + display: inline-block; + font-weight: bold; + margin-right: 2px; } + .select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover { + color: #333; } + +.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline { + float: right; } + +.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice { + margin-left: 5px; + margin-right: auto; } + +.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove { + margin-left: 2px; + margin-right: auto; } + +.select2-container--default.select2-container--focus .select2-selection--multiple { + border: solid black 1px; + outline: 0; } + +.select2-container--default.select2-container--disabled .select2-selection--multiple { + background-color: #eee; + cursor: default; } + +.select2-container--default.select2-container--disabled .select2-selection__choice__remove { + display: none; } + +.select2-container--default.select2-container--open.select2-container--above .select2-selection--single, .select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple { + border-top-left-radius: 0; + border-top-right-radius: 0; } + +.select2-container--default.select2-container--open.select2-container--below .select2-selection--single, .select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; } + +.select2-container--default .select2-search--dropdown .select2-search__field { + border: 1px solid #aaa; } + +.select2-container--default .select2-search--inline .select2-search__field { + background: transparent; + border: none; + outline: 0; + box-shadow: none; + -webkit-appearance: textfield; } + +.select2-container--default .select2-results > .select2-results__options { + max-height: 200px; + overflow-y: auto; } + +.select2-container--default .select2-results__option[role=group] { + padding: 0; } + +.select2-container--default .select2-results__option[aria-disabled=true] { + color: #999; } + +.select2-container--default .select2-results__option[aria-selected=true] { + background-color: #ddd; } + +.select2-container--default .select2-results__option .select2-results__option { + padding-left: 1em; } + .select2-container--default .select2-results__option .select2-results__option .select2-results__group { + padding-left: 0; } + .select2-container--default .select2-results__option .select2-results__option .select2-results__option { + margin-left: -1em; + padding-left: 2em; } + .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -2em; + padding-left: 3em; } + .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -3em; + padding-left: 4em; } + .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -4em; + padding-left: 5em; } + .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option { + margin-left: -5em; + padding-left: 6em; } + +.select2-container--default .select2-results__option--highlighted[aria-selected] { + background-color: #5897fb; + color: white; } + +.select2-container--default .select2-results__group { + cursor: default; + display: block; + padding: 6px; } + +.select2-container--classic .select2-selection--single { + background-color: #f7f7f7; + border: 1px solid #aaa; + border-radius: 4px; + outline: 0; + background-image: -webkit-linear-gradient(top, white 50%, #eeeeee 100%); + background-image: -o-linear-gradient(top, white 50%, #eeeeee 100%); + background-image: linear-gradient(to bottom, white 50%, #eeeeee 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); } + .select2-container--classic .select2-selection--single:focus { + border: 1px solid #5897fb; } + .select2-container--classic .select2-selection--single .select2-selection__rendered { + color: #444; + line-height: 28px; } + .select2-container--classic .select2-selection--single .select2-selection__clear { + cursor: pointer; + float: right; + font-weight: bold; + margin-right: 10px; } + .select2-container--classic .select2-selection--single .select2-selection__placeholder { + color: #999; } + .select2-container--classic .select2-selection--single .select2-selection__arrow { + background-color: #ddd; + border: none; + border-left: 1px solid #aaa; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + height: 26px; + position: absolute; + top: 1px; + right: 1px; + width: 20px; + background-image: -webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%); + background-image: -o-linear-gradient(top, #eeeeee 50%, #cccccc 100%); + background-image: linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0); } + .select2-container--classic .select2-selection--single .select2-selection__arrow b { + border-color: #888 transparent transparent transparent; + border-style: solid; + border-width: 5px 4px 0 4px; + height: 0; + left: 50%; + margin-left: -4px; + margin-top: -2px; + position: absolute; + top: 50%; + width: 0; } + +.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear { + float: left; } + +.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow { + border: none; + border-right: 1px solid #aaa; + border-radius: 0; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + left: 1px; + right: auto; } + +.select2-container--classic.select2-container--open .select2-selection--single { + border: 1px solid #5897fb; } + .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow { + background: transparent; + border: none; } + .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b { + border-color: transparent transparent #888 transparent; + border-width: 0 4px 5px 4px; } + +.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single { + border-top: none; + border-top-left-radius: 0; + border-top-right-radius: 0; + background-image: -webkit-linear-gradient(top, white 0%, #eeeeee 50%); + background-image: -o-linear-gradient(top, white 0%, #eeeeee 50%); + background-image: linear-gradient(to bottom, white 0%, #eeeeee 50%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); } + +.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single { + border-bottom: none; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + background-image: -webkit-linear-gradient(top, #eeeeee 50%, white 100%); + background-image: -o-linear-gradient(top, #eeeeee 50%, white 100%); + background-image: linear-gradient(to bottom, #eeeeee 50%, white 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0); } + +.select2-container--classic .select2-selection--multiple { + background-color: white; + border: 1px solid #aaa; + border-radius: 4px; + cursor: text; + outline: 0; } + .select2-container--classic .select2-selection--multiple:focus { + border: 1px solid #5897fb; } + .select2-container--classic .select2-selection--multiple .select2-selection__rendered { + list-style: none; + margin: 0; + padding: 0 5px; } + .select2-container--classic .select2-selection--multiple .select2-selection__clear { + display: none; } + .select2-container--classic .select2-selection--multiple .select2-selection__choice { + background-color: #e4e4e4; + border: 1px solid #aaa; + border-radius: 4px; + cursor: default; + float: left; + margin-right: 5px; + margin-top: 5px; + padding: 0 5px; } + .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove { + color: #888; + cursor: pointer; + display: inline-block; + font-weight: bold; + margin-right: 2px; } + .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover { + color: #555; } + +.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice { + float: right; + margin-left: 5px; + margin-right: auto; } + +.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove { + margin-left: 2px; + margin-right: auto; } + +.select2-container--classic.select2-container--open .select2-selection--multiple { + border: 1px solid #5897fb; } + +.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple { + border-top: none; + border-top-left-radius: 0; + border-top-right-radius: 0; } + +.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple { + border-bottom: none; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; } + +.select2-container--classic .select2-search--dropdown .select2-search__field { + border: 1px solid #aaa; + outline: 0; } + +.select2-container--classic .select2-search--inline .select2-search__field { + outline: 0; + box-shadow: none; } + +.select2-container--classic .select2-dropdown { + background-color: white; + border: 1px solid transparent; } + +.select2-container--classic .select2-dropdown--above { + border-bottom: none; } + +.select2-container--classic .select2-dropdown--below { + border-top: none; } + +.select2-container--classic .select2-results > .select2-results__options { + max-height: 200px; + overflow-y: auto; } + +.select2-container--classic .select2-results__option[role=group] { + padding: 0; } + +.select2-container--classic .select2-results__option[aria-disabled=true] { + color: grey; } + +.select2-container--classic .select2-results__option--highlighted[aria-selected] { + background-color: #3875d7; + color: white; } + +.select2-container--classic .select2-results__group { + cursor: default; + display: block; + padding: 6px; } + +.select2-container--classic.select2-container--open .select2-dropdown { + border-color: #5897fb; } diff --git a/backend/week3/mydjangoproject/static/admin/css/vendor/select2/select2.min.css b/backend/week3/mydjangoproject/static/admin/css/vendor/select2/select2.min.css new file mode 100644 index 000000000..7c18ad59d --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/css/vendor/select2/select2.min.css @@ -0,0 +1 @@ +.select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{position:relative}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-search--inline{float:left}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;padding:0}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option[aria-selected]{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;height:1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important;white-space:nowrap !important}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--default .select2-selection--multiple .select2-selection__rendered li{list-style:none}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-top:5px;margin-right:10px;padding:1px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{color:#999;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#333}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice,.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline{float:right}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--default .select2-results__option[role=group]{padding:0}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#5897fb;color:white}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, #fff 50%, #eee 100%);background-image:-o-linear-gradient(top, #fff 50%, #eee 100%);background-image:linear-gradient(to bottom, #fff 50%, #eee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-right:10px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eee 50%, #ccc 100%);background-image:-o-linear-gradient(top, #eee 50%, #ccc 100%);background-image:linear-gradient(to bottom, #eee 50%, #ccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #fff 0%, #eee 50%);background-image:-o-linear-gradient(top, #fff 0%, #eee 50%);background-image:linear-gradient(to bottom, #fff 0%, #eee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eee 50%, #fff 100%);background-image:-o-linear-gradient(top, #eee 50%, #fff 100%);background-image:linear-gradient(to bottom, #eee 50%, #fff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__rendered{list-style:none;margin:0;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{color:#888;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{float:right;margin-left:5px;margin-right:auto}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option[role=group]{padding:0}.select2-container--classic .select2-results__option[aria-disabled=true]{color:grey}.select2-container--classic .select2-results__option--highlighted[aria-selected]{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb} diff --git a/backend/week3/mydjangoproject/static/admin/css/widgets.css b/backend/week3/mydjangoproject/static/admin/css/widgets.css new file mode 100644 index 000000000..5f7adcb22 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/css/widgets.css @@ -0,0 +1,603 @@ +/* SELECTOR (FILTER INTERFACE) */ + +.selector { + width: 800px; + float: left; + display: flex; +} + +.selector select { + width: 380px; + height: 17.2em; + flex: 1 0 auto; +} + +.selector-available, .selector-chosen { + width: 380px; + text-align: center; + margin-bottom: 5px; + display: flex; + flex-direction: column; +} + +.selector-available h2, .selector-chosen h2 { + border: 1px solid var(--border-color); + border-radius: 4px 4px 0 0; +} + +.selector-chosen .list-footer-display { + border: 1px solid var(--border-color); + border-top: none; + border-radius: 0 0 4px 4px; + margin: 0 0 10px; + padding: 8px; + text-align: center; + background: var(--primary); + color: var(--header-link-color); + cursor: pointer; +} +.selector-chosen .list-footer-display__clear { + color: var(--breadcrumbs-fg); +} + +.selector-chosen h2 { + background: var(--primary); + color: var(--header-link-color); +} + +.selector .selector-available h2 { + background: var(--darkened-bg); + color: var(--body-quiet-color); +} + +.selector .selector-filter { + border: 1px solid var(--border-color); + border-width: 0 1px; + padding: 8px; + color: var(--body-quiet-color); + font-size: 0.625rem; + margin: 0; + text-align: left; +} + +.selector .selector-filter label, +.inline-group .aligned .selector .selector-filter label { + float: left; + margin: 7px 0 0; + width: 18px; + height: 18px; + padding: 0; + overflow: hidden; + line-height: 1; +} + +.selector .selector-available input, +.selector .selector-chosen input { + width: 320px; + margin-left: 8px; +} + +.selector ul.selector-chooser { + align-self: center; + width: 22px; + background-color: var(--selected-bg); + border-radius: 10px; + margin: 0 5px; + padding: 0; + transform: translateY(-17px); +} + +.selector-chooser li { + margin: 0; + padding: 3px; + list-style-type: none; +} + +.selector select { + padding: 0 10px; + margin: 0 0 10px; + border-radius: 0 0 4px 4px; +} +.selector .selector-chosen--with-filtered select { + margin: 0; + border-radius: 0; + height: 14em; +} + +.selector .selector-chosen:not(.selector-chosen--with-filtered) .list-footer-display { + display: none; +} + +.selector-add, .selector-remove { + width: 16px; + height: 16px; + display: block; + text-indent: -3000px; + overflow: hidden; + cursor: default; + opacity: 0.55; +} + +.active.selector-add, .active.selector-remove { + opacity: 1; +} + +.active.selector-add:hover, .active.selector-remove:hover { + cursor: pointer; +} + +.selector-add { + background: url(../img/selector-icons.svg) 0 -96px no-repeat; +} + +.active.selector-add:focus, .active.selector-add:hover { + background-position: 0 -112px; +} + +.selector-remove { + background: url(../img/selector-icons.svg) 0 -64px no-repeat; +} + +.active.selector-remove:focus, .active.selector-remove:hover { + background-position: 0 -80px; +} + +a.selector-chooseall, a.selector-clearall { + display: inline-block; + height: 16px; + text-align: left; + margin: 1px auto 3px; + overflow: hidden; + font-weight: bold; + line-height: 16px; + color: var(--body-quiet-color); + text-decoration: none; + opacity: 0.55; +} + +a.active.selector-chooseall:focus, a.active.selector-clearall:focus, +a.active.selector-chooseall:hover, a.active.selector-clearall:hover { + color: var(--link-fg); +} + +a.active.selector-chooseall, a.active.selector-clearall { + opacity: 1; +} + +a.active.selector-chooseall:hover, a.active.selector-clearall:hover { + cursor: pointer; +} + +a.selector-chooseall { + padding: 0 18px 0 0; + background: url(../img/selector-icons.svg) right -160px no-repeat; + cursor: default; +} + +a.active.selector-chooseall:focus, a.active.selector-chooseall:hover { + background-position: 100% -176px; +} + +a.selector-clearall { + padding: 0 0 0 18px; + background: url(../img/selector-icons.svg) 0 -128px no-repeat; + cursor: default; +} + +a.active.selector-clearall:focus, a.active.selector-clearall:hover { + background-position: 0 -144px; +} + +/* STACKED SELECTORS */ + +.stacked { + float: left; + width: 490px; + display: block; +} + +.stacked select { + width: 480px; + height: 10.1em; +} + +.stacked .selector-available, .stacked .selector-chosen { + width: 480px; +} + +.stacked .selector-available { + margin-bottom: 0; +} + +.stacked .selector-available input { + width: 422px; +} + +.stacked ul.selector-chooser { + height: 22px; + width: 50px; + margin: 0 0 10px 40%; + background-color: #eee; + border-radius: 10px; + transform: none; +} + +.stacked .selector-chooser li { + float: left; + padding: 3px 3px 3px 5px; +} + +.stacked .selector-chooseall, .stacked .selector-clearall { + display: none; +} + +.stacked .selector-add { + background: url(../img/selector-icons.svg) 0 -32px no-repeat; + cursor: default; +} + +.stacked .active.selector-add { + background-position: 0 -32px; + cursor: pointer; +} + +.stacked .active.selector-add:focus, .stacked .active.selector-add:hover { + background-position: 0 -48px; + cursor: pointer; +} + +.stacked .selector-remove { + background: url(../img/selector-icons.svg) 0 0 no-repeat; + cursor: default; +} + +.stacked .active.selector-remove { + background-position: 0 0px; + cursor: pointer; +} + +.stacked .active.selector-remove:focus, .stacked .active.selector-remove:hover { + background-position: 0 -16px; + cursor: pointer; +} + +.selector .help-icon { + background: url(../img/icon-unknown.svg) 0 0 no-repeat; + display: inline-block; + vertical-align: middle; + margin: -2px 0 0 2px; + width: 13px; + height: 13px; +} + +.selector .selector-chosen .help-icon { + background: url(../img/icon-unknown-alt.svg) 0 0 no-repeat; +} + +.selector .search-label-icon { + background: url(../img/search.svg) 0 0 no-repeat; + display: inline-block; + height: 1.125rem; + width: 1.125rem; +} + +/* DATE AND TIME */ + +p.datetime { + line-height: 20px; + margin: 0; + padding: 0; + color: var(--body-quiet-color); + font-weight: bold; +} + +.datetime span { + white-space: nowrap; + font-weight: normal; + font-size: 0.6875rem; + color: var(--body-quiet-color); +} + +.datetime input, .form-row .datetime input.vDateField, .form-row .datetime input.vTimeField { + margin-left: 5px; + margin-bottom: 4px; +} + +table p.datetime { + font-size: 0.6875rem; + margin-left: 0; + padding-left: 0; +} + +.datetimeshortcuts .clock-icon, .datetimeshortcuts .date-icon { + position: relative; + display: inline-block; + vertical-align: middle; + height: 16px; + width: 16px; + overflow: hidden; +} + +.datetimeshortcuts .clock-icon { + background: url(../img/icon-clock.svg) 0 0 no-repeat; +} + +.datetimeshortcuts a:focus .clock-icon, +.datetimeshortcuts a:hover .clock-icon { + background-position: 0 -16px; +} + +.datetimeshortcuts .date-icon { + background: url(../img/icon-calendar.svg) 0 0 no-repeat; + top: -1px; +} + +.datetimeshortcuts a:focus .date-icon, +.datetimeshortcuts a:hover .date-icon { + background-position: 0 -16px; +} + +.timezonewarning { + font-size: 0.6875rem; + color: var(--body-quiet-color); +} + +/* URL */ + +p.url { + line-height: 20px; + margin: 0; + padding: 0; + color: var(--body-quiet-color); + font-size: 0.6875rem; + font-weight: bold; +} + +.url a { + font-weight: normal; +} + +/* FILE UPLOADS */ + +p.file-upload { + line-height: 20px; + margin: 0; + padding: 0; + color: var(--body-quiet-color); + font-size: 0.6875rem; + font-weight: bold; +} + +.file-upload a { + font-weight: normal; +} + +.file-upload .deletelink { + margin-left: 5px; +} + +span.clearable-file-input label { + color: var(--body-fg); + font-size: 0.6875rem; + display: inline; + float: none; +} + +/* CALENDARS & CLOCKS */ + +.calendarbox, .clockbox { + margin: 5px auto; + font-size: 0.75rem; + width: 19em; + text-align: center; + background: var(--body-bg); + color: var(--body-fg); + border: 1px solid var(--hairline-color); + border-radius: 4px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15); + overflow: hidden; + position: relative; +} + +.clockbox { + width: auto; +} + +.calendar { + margin: 0; + padding: 0; +} + +.calendar table { + margin: 0; + padding: 0; + border-collapse: collapse; + background: white; + width: 100%; +} + +.calendar caption, .calendarbox h2 { + margin: 0; + text-align: center; + border-top: none; + font-weight: 700; + font-size: 0.75rem; + color: #333; + background: var(--accent); +} + +.calendar th { + padding: 8px 5px; + background: var(--darkened-bg); + border-bottom: 1px solid var(--border-color); + font-weight: 400; + font-size: 0.75rem; + text-align: center; + color: var(--body-quiet-color); +} + +.calendar td { + font-weight: 400; + font-size: 0.75rem; + text-align: center; + padding: 0; + border-top: 1px solid var(--hairline-color); + border-bottom: none; +} + +.calendar td.selected a { + background: var(--primary); + color: var(--button-fg); +} + +.calendar td.nonday { + background: var(--darkened-bg); +} + +.calendar td.today a { + font-weight: 700; +} + +.calendar td a, .timelist a { + display: block; + font-weight: 400; + padding: 6px; + text-decoration: none; + color: var(--body-quiet-color); +} + +.calendar td a:focus, .timelist a:focus, +.calendar td a:hover, .timelist a:hover { + background: var(--primary); + color: white; +} + +.calendar td a:active, .timelist a:active { + background: var(--header-bg); + color: white; +} + +.calendarnav { + font-size: 0.625rem; + text-align: center; + color: #ccc; + margin: 0; + padding: 1px 3px; +} + +.calendarnav a:link, #calendarnav a:visited, +#calendarnav a:focus, #calendarnav a:hover { + color: var(--body-quiet-color); +} + +.calendar-shortcuts { + background: var(--body-bg); + color: var(--body-quiet-color); + font-size: 0.6875rem; + line-height: 0.6875rem; + border-top: 1px solid var(--hairline-color); + padding: 8px 0; +} + +.calendarbox .calendarnav-previous, .calendarbox .calendarnav-next { + display: block; + position: absolute; + top: 8px; + width: 15px; + height: 15px; + text-indent: -9999px; + padding: 0; +} + +.calendarnav-previous { + left: 10px; + background: url(../img/calendar-icons.svg) 0 0 no-repeat; +} + +.calendarbox .calendarnav-previous:focus, +.calendarbox .calendarnav-previous:hover { + background-position: 0 -15px; +} + +.calendarnav-next { + right: 10px; + background: url(../img/calendar-icons.svg) 0 -30px no-repeat; +} + +.calendarbox .calendarnav-next:focus, +.calendarbox .calendarnav-next:hover { + background-position: 0 -45px; +} + +.calendar-cancel { + margin: 0; + padding: 4px 0; + font-size: 0.75rem; + background: #eee; + border-top: 1px solid var(--border-color); + color: var(--body-fg); +} + +.calendar-cancel:focus, .calendar-cancel:hover { + background: #ddd; +} + +.calendar-cancel a { + color: black; + display: block; +} + +ul.timelist, .timelist li { + list-style-type: none; + margin: 0; + padding: 0; +} + +.timelist a { + padding: 2px; +} + +/* EDIT INLINE */ + +.inline-deletelink { + float: right; + text-indent: -9999px; + background: url(../img/inline-delete.svg) 0 0 no-repeat; + width: 16px; + height: 16px; + border: 0px none; +} + +.inline-deletelink:focus, .inline-deletelink:hover { + cursor: pointer; +} + +/* RELATED WIDGET WRAPPER */ +.related-widget-wrapper { + float: left; /* display properly in form rows with multiple fields */ + overflow: hidden; /* clear floated contents */ +} + +.related-widget-wrapper-link { + opacity: 0.3; +} + +.related-widget-wrapper-link:link { + opacity: .8; +} + +.related-widget-wrapper-link:link:focus, +.related-widget-wrapper-link:link:hover { + opacity: 1; +} + +select + .related-widget-wrapper-link, +.related-widget-wrapper-link + .related-widget-wrapper-link { + margin-left: 7px; +} + +/* GIS MAPS */ +.dj_map { + width: 600px; + height: 400px; +} diff --git a/backend/week3/mydjangoproject/static/admin/img/LICENSE b/backend/week3/mydjangoproject/static/admin/img/LICENSE new file mode 100644 index 000000000..a4faaa1df --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014 Code Charm Ltd + +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. diff --git a/backend/week3/mydjangoproject/static/admin/img/README.txt b/backend/week3/mydjangoproject/static/admin/img/README.txt new file mode 100644 index 000000000..4eb2e492a --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/README.txt @@ -0,0 +1,7 @@ +All icons are taken from Font Awesome (http://fontawesome.io/) project. +The Font Awesome font is licensed under the SIL OFL 1.1: +- https://scripts.sil.org/OFL + +SVG icons source: https://github.com/encharm/Font-Awesome-SVG-PNG +Font-Awesome-SVG-PNG is licensed under the MIT license (see file license +in current folder). diff --git a/backend/week3/mydjangoproject/static/admin/img/calendar-icons.svg b/backend/week3/mydjangoproject/static/admin/img/calendar-icons.svg new file mode 100644 index 000000000..dbf21c39d --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/calendar-icons.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/backend/week3/mydjangoproject/static/admin/img/gis/move_vertex_off.svg b/backend/week3/mydjangoproject/static/admin/img/gis/move_vertex_off.svg new file mode 100644 index 000000000..228854f3b --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/gis/move_vertex_off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backend/week3/mydjangoproject/static/admin/img/gis/move_vertex_on.svg b/backend/week3/mydjangoproject/static/admin/img/gis/move_vertex_on.svg new file mode 100644 index 000000000..96b87fdd7 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/gis/move_vertex_on.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backend/week3/mydjangoproject/static/admin/img/icon-addlink.svg b/backend/week3/mydjangoproject/static/admin/img/icon-addlink.svg new file mode 100644 index 000000000..e004fb162 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/icon-addlink.svg @@ -0,0 +1,3 @@ + + + diff --git a/backend/week3/mydjangoproject/static/admin/img/icon-alert.svg b/backend/week3/mydjangoproject/static/admin/img/icon-alert.svg new file mode 100644 index 000000000..e51ea83f5 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/icon-alert.svg @@ -0,0 +1,3 @@ + + + diff --git a/backend/week3/mydjangoproject/static/admin/img/icon-calendar.svg b/backend/week3/mydjangoproject/static/admin/img/icon-calendar.svg new file mode 100644 index 000000000..97910a994 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/icon-calendar.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/backend/week3/mydjangoproject/static/admin/img/icon-changelink.svg b/backend/week3/mydjangoproject/static/admin/img/icon-changelink.svg new file mode 100644 index 000000000..bbb137aa0 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/icon-changelink.svg @@ -0,0 +1,3 @@ + + + diff --git a/backend/week3/mydjangoproject/static/admin/img/icon-clock.svg b/backend/week3/mydjangoproject/static/admin/img/icon-clock.svg new file mode 100644 index 000000000..bf9985d3f --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/icon-clock.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/backend/week3/mydjangoproject/static/admin/img/icon-deletelink.svg b/backend/week3/mydjangoproject/static/admin/img/icon-deletelink.svg new file mode 100644 index 000000000..4059b1554 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/icon-deletelink.svg @@ -0,0 +1,3 @@ + + + diff --git a/backend/week3/mydjangoproject/static/admin/img/icon-no.svg b/backend/week3/mydjangoproject/static/admin/img/icon-no.svg new file mode 100644 index 000000000..2e0d3832c --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/icon-no.svg @@ -0,0 +1,3 @@ + + + diff --git a/backend/week3/mydjangoproject/static/admin/img/icon-unknown-alt.svg b/backend/week3/mydjangoproject/static/admin/img/icon-unknown-alt.svg new file mode 100644 index 000000000..1c6b99fc0 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/icon-unknown-alt.svg @@ -0,0 +1,3 @@ + + + diff --git a/backend/week3/mydjangoproject/static/admin/img/icon-unknown.svg b/backend/week3/mydjangoproject/static/admin/img/icon-unknown.svg new file mode 100644 index 000000000..50b4f9727 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/icon-unknown.svg @@ -0,0 +1,3 @@ + + + diff --git a/backend/week3/mydjangoproject/static/admin/img/icon-viewlink.svg b/backend/week3/mydjangoproject/static/admin/img/icon-viewlink.svg new file mode 100644 index 000000000..a1ca1d3f4 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/icon-viewlink.svg @@ -0,0 +1,3 @@ + + + diff --git a/backend/week3/mydjangoproject/static/admin/img/icon-yes.svg b/backend/week3/mydjangoproject/static/admin/img/icon-yes.svg new file mode 100644 index 000000000..5883d877e --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/icon-yes.svg @@ -0,0 +1,3 @@ + + + diff --git a/backend/week3/mydjangoproject/static/admin/img/inline-delete.svg b/backend/week3/mydjangoproject/static/admin/img/inline-delete.svg new file mode 100644 index 000000000..17d1ad67c --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/inline-delete.svg @@ -0,0 +1,3 @@ + + + diff --git a/backend/week3/mydjangoproject/static/admin/img/search.svg b/backend/week3/mydjangoproject/static/admin/img/search.svg new file mode 100644 index 000000000..c8c69b2ac --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/search.svg @@ -0,0 +1,3 @@ + + + diff --git a/backend/week3/mydjangoproject/static/admin/img/selector-icons.svg b/backend/week3/mydjangoproject/static/admin/img/selector-icons.svg new file mode 100644 index 000000000..926b8e21b --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/selector-icons.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/backend/week3/mydjangoproject/static/admin/img/sorting-icons.svg b/backend/week3/mydjangoproject/static/admin/img/sorting-icons.svg new file mode 100644 index 000000000..7c31ec911 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/sorting-icons.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/backend/week3/mydjangoproject/static/admin/img/tooltag-add.svg b/backend/week3/mydjangoproject/static/admin/img/tooltag-add.svg new file mode 100644 index 000000000..1ca64ae5b --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/tooltag-add.svg @@ -0,0 +1,3 @@ + + + diff --git a/backend/week3/mydjangoproject/static/admin/img/tooltag-arrowright.svg b/backend/week3/mydjangoproject/static/admin/img/tooltag-arrowright.svg new file mode 100644 index 000000000..b664d6193 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/img/tooltag-arrowright.svg @@ -0,0 +1,3 @@ + + + diff --git a/backend/week3/mydjangoproject/static/admin/js/SelectBox.js b/backend/week3/mydjangoproject/static/admin/js/SelectBox.js new file mode 100644 index 000000000..3db4ec7fa --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/SelectBox.js @@ -0,0 +1,116 @@ +'use strict'; +{ + const SelectBox = { + cache: {}, + init: function(id) { + const box = document.getElementById(id); + SelectBox.cache[id] = []; + const cache = SelectBox.cache[id]; + for (const node of box.options) { + cache.push({value: node.value, text: node.text, displayed: 1}); + } + }, + redisplay: function(id) { + // Repopulate HTML select box from cache + const box = document.getElementById(id); + const scroll_value_from_top = box.scrollTop; + box.innerHTML = ''; + for (const node of SelectBox.cache[id]) { + if (node.displayed) { + const new_option = new Option(node.text, node.value, false, false); + // Shows a tooltip when hovering over the option + new_option.title = node.text; + box.appendChild(new_option); + } + } + box.scrollTop = scroll_value_from_top; + }, + filter: function(id, text) { + // Redisplay the HTML select box, displaying only the choices containing ALL + // the words in text. (It's an AND search.) + const tokens = text.toLowerCase().split(/\s+/); + for (const node of SelectBox.cache[id]) { + node.displayed = 1; + const node_text = node.text.toLowerCase(); + for (const token of tokens) { + if (!node_text.includes(token)) { + node.displayed = 0; + break; // Once the first token isn't found we're done + } + } + } + SelectBox.redisplay(id); + }, + get_hidden_node_count(id) { + const cache = SelectBox.cache[id] || []; + return cache.filter(node => node.displayed === 0).length; + }, + delete_from_cache: function(id, value) { + let delete_index = null; + const cache = SelectBox.cache[id]; + for (const [i, node] of cache.entries()) { + if (node.value === value) { + delete_index = i; + break; + } + } + cache.splice(delete_index, 1); + }, + add_to_cache: function(id, option) { + SelectBox.cache[id].push({value: option.value, text: option.text, displayed: 1}); + }, + cache_contains: function(id, value) { + // Check if an item is contained in the cache + for (const node of SelectBox.cache[id]) { + if (node.value === value) { + return true; + } + } + return false; + }, + move: function(from, to) { + const from_box = document.getElementById(from); + for (const option of from_box.options) { + const option_value = option.value; + if (option.selected && SelectBox.cache_contains(from, option_value)) { + SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1}); + SelectBox.delete_from_cache(from, option_value); + } + } + SelectBox.redisplay(from); + SelectBox.redisplay(to); + }, + move_all: function(from, to) { + const from_box = document.getElementById(from); + for (const option of from_box.options) { + const option_value = option.value; + if (SelectBox.cache_contains(from, option_value)) { + SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1}); + SelectBox.delete_from_cache(from, option_value); + } + } + SelectBox.redisplay(from); + SelectBox.redisplay(to); + }, + sort: function(id) { + SelectBox.cache[id].sort(function(a, b) { + a = a.text.toLowerCase(); + b = b.text.toLowerCase(); + if (a > b) { + return 1; + } + if (a < b) { + return -1; + } + return 0; + } ); + }, + select_all: function(id) { + const box = document.getElementById(id); + for (const option of box.options) { + option.selected = true; + } + } + }; + window.SelectBox = SelectBox; +} diff --git a/backend/week3/mydjangoproject/static/admin/js/SelectFilter2.js b/backend/week3/mydjangoproject/static/admin/js/SelectFilter2.js new file mode 100644 index 000000000..9a4e0a3a9 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/SelectFilter2.js @@ -0,0 +1,283 @@ +/*global SelectBox, gettext, interpolate, quickElement, SelectFilter*/ +/* +SelectFilter2 - Turns a multiple-select box into a filter interface. + +Requires core.js and SelectBox.js. +*/ +'use strict'; +{ + window.SelectFilter = { + init: function(field_id, field_name, is_stacked) { + if (field_id.match(/__prefix__/)) { + // Don't initialize on empty forms. + return; + } + const from_box = document.getElementById(field_id); + from_box.id += '_from'; // change its ID + from_box.className = 'filtered'; + + for (const p of from_box.parentNode.getElementsByTagName('p')) { + if (p.classList.contains("info")) { + // Remove

, because it just gets in the way. + from_box.parentNode.removeChild(p); + } else if (p.classList.contains("help")) { + // Move help text up to the top so it isn't below the select + // boxes or wrapped off on the side to the right of the add + // button: + from_box.parentNode.insertBefore(p, from_box.parentNode.firstChild); + } + } + + //

or
+ const selector_div = quickElement('div', from_box.parentNode); + selector_div.className = is_stacked ? 'selector stacked' : 'selector'; + + //
+ const selector_available = quickElement('div', selector_div); + selector_available.className = 'selector-available'; + const title_available = quickElement('h2', selector_available, interpolate(gettext('Available %s') + ' ', [field_name])); + quickElement( + 'span', title_available, '', + 'class', 'help help-tooltip help-icon', + 'title', interpolate( + gettext( + 'This is the list of available %s. You may choose some by ' + + 'selecting them in the box below and then clicking the ' + + '"Choose" arrow between the two boxes.' + ), + [field_name] + ) + ); + + const filter_p = quickElement('p', selector_available, '', 'id', field_id + '_filter'); + filter_p.className = 'selector-filter'; + + const search_filter_label = quickElement('label', filter_p, '', 'for', field_id + '_input'); + + quickElement( + 'span', search_filter_label, '', + 'class', 'help-tooltip search-label-icon', + 'title', interpolate(gettext("Type into this box to filter down the list of available %s."), [field_name]) + ); + + filter_p.appendChild(document.createTextNode(' ')); + + const filter_input = quickElement('input', filter_p, '', 'type', 'text', 'placeholder', gettext("Filter")); + filter_input.id = field_id + '_input'; + + selector_available.appendChild(from_box); + const choose_all = quickElement('a', selector_available, gettext('Choose all'), 'title', interpolate(gettext('Click to choose all %s at once.'), [field_name]), 'href', '#', 'id', field_id + '_add_all_link'); + choose_all.className = 'selector-chooseall'; + + //
    + const selector_chooser = quickElement('ul', selector_div); + selector_chooser.className = 'selector-chooser'; + const add_link = quickElement('a', quickElement('li', selector_chooser), gettext('Choose'), 'title', gettext('Choose'), 'href', '#', 'id', field_id + '_add_link'); + add_link.className = 'selector-add'; + const remove_link = quickElement('a', quickElement('li', selector_chooser), gettext('Remove'), 'title', gettext('Remove'), 'href', '#', 'id', field_id + '_remove_link'); + remove_link.className = 'selector-remove'; + + //
    + const selector_chosen = quickElement('div', selector_div, '', 'id', field_id + '_selector_chosen'); + selector_chosen.className = 'selector-chosen'; + const title_chosen = quickElement('h2', selector_chosen, interpolate(gettext('Chosen %s') + ' ', [field_name])); + quickElement( + 'span', title_chosen, '', + 'class', 'help help-tooltip help-icon', + 'title', interpolate( + gettext( + 'This is the list of chosen %s. You may remove some by ' + + 'selecting them in the box below and then clicking the ' + + '"Remove" arrow between the two boxes.' + ), + [field_name] + ) + ); + + const filter_selected_p = quickElement('p', selector_chosen, '', 'id', field_id + '_filter_selected'); + filter_selected_p.className = 'selector-filter'; + + const search_filter_selected_label = quickElement('label', filter_selected_p, '', 'for', field_id + '_selected_input'); + + quickElement( + 'span', search_filter_selected_label, '', + 'class', 'help-tooltip search-label-icon', + 'title', interpolate(gettext("Type into this box to filter down the list of selected %s."), [field_name]) + ); + + filter_selected_p.appendChild(document.createTextNode(' ')); + + const filter_selected_input = quickElement('input', filter_selected_p, '', 'type', 'text', 'placeholder', gettext("Filter")); + filter_selected_input.id = field_id + '_selected_input'; + + const to_box = quickElement('select', selector_chosen, '', 'id', field_id + '_to', 'multiple', '', 'size', from_box.size, 'name', from_box.name); + to_box.className = 'filtered'; + + const warning_footer = quickElement('div', selector_chosen, '', 'class', 'list-footer-display'); + quickElement('span', warning_footer, '', 'id', field_id + '_list-footer-display-text'); + quickElement('span', warning_footer, ' (click to clear)', 'class', 'list-footer-display__clear'); + + const clear_all = quickElement('a', selector_chosen, gettext('Remove all'), 'title', interpolate(gettext('Click to remove all chosen %s at once.'), [field_name]), 'href', '#', 'id', field_id + '_remove_all_link'); + clear_all.className = 'selector-clearall'; + + from_box.name = from_box.name + '_old'; + + // Set up the JavaScript event handlers for the select box filter interface + const move_selection = function(e, elem, move_func, from, to) { + if (elem.classList.contains('active')) { + move_func(from, to); + SelectFilter.refresh_icons(field_id); + SelectFilter.refresh_filtered_selects(field_id); + SelectFilter.refresh_filtered_warning(field_id); + } + e.preventDefault(); + }; + choose_all.addEventListener('click', function(e) { + move_selection(e, this, SelectBox.move_all, field_id + '_from', field_id + '_to'); + }); + add_link.addEventListener('click', function(e) { + move_selection(e, this, SelectBox.move, field_id + '_from', field_id + '_to'); + }); + remove_link.addEventListener('click', function(e) { + move_selection(e, this, SelectBox.move, field_id + '_to', field_id + '_from'); + }); + clear_all.addEventListener('click', function(e) { + move_selection(e, this, SelectBox.move_all, field_id + '_to', field_id + '_from'); + }); + warning_footer.addEventListener('click', function(e) { + filter_selected_input.value = ''; + SelectBox.filter(field_id + '_to', ''); + SelectFilter.refresh_filtered_warning(field_id); + SelectFilter.refresh_icons(field_id); + }); + filter_input.addEventListener('keypress', function(e) { + SelectFilter.filter_key_press(e, field_id, '_from', '_to'); + }); + filter_input.addEventListener('keyup', function(e) { + SelectFilter.filter_key_up(e, field_id, '_from'); + }); + filter_input.addEventListener('keydown', function(e) { + SelectFilter.filter_key_down(e, field_id, '_from', '_to'); + }); + filter_selected_input.addEventListener('keypress', function(e) { + SelectFilter.filter_key_press(e, field_id, '_to', '_from'); + }); + filter_selected_input.addEventListener('keyup', function(e) { + SelectFilter.filter_key_up(e, field_id, '_to', '_selected_input'); + }); + filter_selected_input.addEventListener('keydown', function(e) { + SelectFilter.filter_key_down(e, field_id, '_to', '_from'); + }); + selector_div.addEventListener('change', function(e) { + if (e.target.tagName === 'SELECT') { + SelectFilter.refresh_icons(field_id); + } + }); + selector_div.addEventListener('dblclick', function(e) { + if (e.target.tagName === 'OPTION') { + if (e.target.closest('select').id === field_id + '_to') { + SelectBox.move(field_id + '_to', field_id + '_from'); + } else { + SelectBox.move(field_id + '_from', field_id + '_to'); + } + SelectFilter.refresh_icons(field_id); + } + }); + from_box.closest('form').addEventListener('submit', function() { + SelectBox.filter(field_id + '_to', ''); + SelectBox.select_all(field_id + '_to'); + }); + SelectBox.init(field_id + '_from'); + SelectBox.init(field_id + '_to'); + // Move selected from_box options to to_box + SelectBox.move(field_id + '_from', field_id + '_to'); + + // Initial icon refresh + SelectFilter.refresh_icons(field_id); + }, + any_selected: function(field) { + // Temporarily add the required attribute and check validity. + field.required = true; + const any_selected = field.checkValidity(); + field.required = false; + return any_selected; + }, + refresh_filtered_warning: function(field_id) { + const count = SelectBox.get_hidden_node_count(field_id + '_to'); + const selector = document.getElementById(field_id + '_selector_chosen'); + const warning = document.getElementById(field_id + '_list-footer-display-text'); + selector.className = selector.className.replace('selector-chosen--with-filtered', ''); + warning.textContent = interpolate(ngettext( + '%s selected option not visible', + '%s selected options not visible', + count + ), [count]); + if(count > 0) { + selector.className += ' selector-chosen--with-filtered'; + } + }, + refresh_filtered_selects: function(field_id) { + SelectBox.filter(field_id + '_from', document.getElementById(field_id + "_input").value); + SelectBox.filter(field_id + '_to', document.getElementById(field_id + "_selected_input").value); + }, + refresh_icons: function(field_id) { + const from = document.getElementById(field_id + '_from'); + const to = document.getElementById(field_id + '_to'); + // Active if at least one item is selected + document.getElementById(field_id + '_add_link').classList.toggle('active', SelectFilter.any_selected(from)); + document.getElementById(field_id + '_remove_link').classList.toggle('active', SelectFilter.any_selected(to)); + // Active if the corresponding box isn't empty + document.getElementById(field_id + '_add_all_link').classList.toggle('active', from.querySelector('option')); + document.getElementById(field_id + '_remove_all_link').classList.toggle('active', to.querySelector('option')); + SelectFilter.refresh_filtered_warning(field_id); + }, + filter_key_press: function(event, field_id, source, target) { + const source_box = document.getElementById(field_id + source); + // don't submit form if user pressed Enter + if ((event.which && event.which === 13) || (event.keyCode && event.keyCode === 13)) { + source_box.selectedIndex = 0; + SelectBox.move(field_id + source, field_id + target); + source_box.selectedIndex = 0; + event.preventDefault(); + } + }, + filter_key_up: function(event, field_id, source, filter_input) { + const input = filter_input || '_input'; + const source_box = document.getElementById(field_id + source); + const temp = source_box.selectedIndex; + SelectBox.filter(field_id + source, document.getElementById(field_id + input).value); + source_box.selectedIndex = temp; + SelectFilter.refresh_filtered_warning(field_id); + SelectFilter.refresh_icons(field_id); + }, + filter_key_down: function(event, field_id, source, target) { + const source_box = document.getElementById(field_id + source); + // right key (39) or left key (37) + const direction = source === '_from' ? 39 : 37; + // right arrow -- move across + if ((event.which && event.which === direction) || (event.keyCode && event.keyCode === direction)) { + const old_index = source_box.selectedIndex; + SelectBox.move(field_id + source, field_id + target); + SelectFilter.refresh_filtered_selects(field_id); + SelectFilter.refresh_filtered_warning(field_id); + source_box.selectedIndex = (old_index === source_box.length) ? source_box.length - 1 : old_index; + return; + } + // down arrow -- wrap around + if ((event.which && event.which === 40) || (event.keyCode && event.keyCode === 40)) { + source_box.selectedIndex = (source_box.length === source_box.selectedIndex + 1) ? 0 : source_box.selectedIndex + 1; + } + // up arrow -- wrap around + if ((event.which && event.which === 38) || (event.keyCode && event.keyCode === 38)) { + source_box.selectedIndex = (source_box.selectedIndex === 0) ? source_box.length - 1 : source_box.selectedIndex - 1; + } + } + }; + + window.addEventListener('load', function(e) { + document.querySelectorAll('select.selectfilter, select.selectfilterstacked').forEach(function(el) { + const data = el.dataset; + SelectFilter.init(el.id, data.fieldName, parseInt(data.isStacked, 10)); + }); + }); +} diff --git a/backend/week3/mydjangoproject/static/admin/js/actions.js b/backend/week3/mydjangoproject/static/admin/js/actions.js new file mode 100644 index 000000000..20a5c1435 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/actions.js @@ -0,0 +1,201 @@ +/*global gettext, interpolate, ngettext*/ +'use strict'; +{ + function show(selector) { + document.querySelectorAll(selector).forEach(function(el) { + el.classList.remove('hidden'); + }); + } + + function hide(selector) { + document.querySelectorAll(selector).forEach(function(el) { + el.classList.add('hidden'); + }); + } + + function showQuestion(options) { + hide(options.acrossClears); + show(options.acrossQuestions); + hide(options.allContainer); + } + + function showClear(options) { + show(options.acrossClears); + hide(options.acrossQuestions); + document.querySelector(options.actionContainer).classList.remove(options.selectedClass); + show(options.allContainer); + hide(options.counterContainer); + } + + function reset(options) { + hide(options.acrossClears); + hide(options.acrossQuestions); + hide(options.allContainer); + show(options.counterContainer); + } + + function clearAcross(options) { + reset(options); + const acrossInputs = document.querySelectorAll(options.acrossInput); + acrossInputs.forEach(function(acrossInput) { + acrossInput.value = 0; + }); + document.querySelector(options.actionContainer).classList.remove(options.selectedClass); + } + + function checker(actionCheckboxes, options, checked) { + if (checked) { + showQuestion(options); + } else { + reset(options); + } + actionCheckboxes.forEach(function(el) { + el.checked = checked; + el.closest('tr').classList.toggle(options.selectedClass, checked); + }); + } + + function updateCounter(actionCheckboxes, options) { + const sel = Array.from(actionCheckboxes).filter(function(el) { + return el.checked; + }).length; + const counter = document.querySelector(options.counterContainer); + // data-actions-icnt is defined in the generated HTML + // and contains the total amount of objects in the queryset + const actions_icnt = Number(counter.dataset.actionsIcnt); + counter.textContent = interpolate( + ngettext('%(sel)s of %(cnt)s selected', '%(sel)s of %(cnt)s selected', sel), { + sel: sel, + cnt: actions_icnt + }, true); + const allToggle = document.getElementById(options.allToggleId); + allToggle.checked = sel === actionCheckboxes.length; + if (allToggle.checked) { + showQuestion(options); + } else { + clearAcross(options); + } + } + + const defaults = { + actionContainer: "div.actions", + counterContainer: "span.action-counter", + allContainer: "div.actions span.all", + acrossInput: "div.actions input.select-across", + acrossQuestions: "div.actions span.question", + acrossClears: "div.actions span.clear", + allToggleId: "action-toggle", + selectedClass: "selected" + }; + + window.Actions = function(actionCheckboxes, options) { + options = Object.assign({}, defaults, options); + let list_editable_changed = false; + let lastChecked = null; + let shiftPressed = false; + + document.addEventListener('keydown', (event) => { + shiftPressed = event.shiftKey; + }); + + document.addEventListener('keyup', (event) => { + shiftPressed = event.shiftKey; + }); + + document.getElementById(options.allToggleId).addEventListener('click', function(event) { + checker(actionCheckboxes, options, this.checked); + updateCounter(actionCheckboxes, options); + }); + + document.querySelectorAll(options.acrossQuestions + " a").forEach(function(el) { + el.addEventListener('click', function(event) { + event.preventDefault(); + const acrossInputs = document.querySelectorAll(options.acrossInput); + acrossInputs.forEach(function(acrossInput) { + acrossInput.value = 1; + }); + showClear(options); + }); + }); + + document.querySelectorAll(options.acrossClears + " a").forEach(function(el) { + el.addEventListener('click', function(event) { + event.preventDefault(); + document.getElementById(options.allToggleId).checked = false; + clearAcross(options); + checker(actionCheckboxes, options, false); + updateCounter(actionCheckboxes, options); + }); + }); + + function affectedCheckboxes(target, withModifier) { + const multiSelect = (lastChecked && withModifier && lastChecked !== target); + if (!multiSelect) { + return [target]; + } + const checkboxes = Array.from(actionCheckboxes); + const targetIndex = checkboxes.findIndex(el => el === target); + const lastCheckedIndex = checkboxes.findIndex(el => el === lastChecked); + const startIndex = Math.min(targetIndex, lastCheckedIndex); + const endIndex = Math.max(targetIndex, lastCheckedIndex); + const filtered = checkboxes.filter((el, index) => (startIndex <= index) && (index <= endIndex)); + return filtered; + }; + + Array.from(document.getElementById('result_list').tBodies).forEach(function(el) { + el.addEventListener('change', function(event) { + const target = event.target; + if (target.classList.contains('action-select')) { + const checkboxes = affectedCheckboxes(target, shiftPressed); + checker(checkboxes, options, target.checked); + updateCounter(actionCheckboxes, options); + lastChecked = target; + } else { + list_editable_changed = true; + } + }); + }); + + document.querySelector('#changelist-form button[name=index]').addEventListener('click', function(event) { + if (list_editable_changed) { + const confirmed = confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost.")); + if (!confirmed) { + event.preventDefault(); + } + } + }); + + const el = document.querySelector('#changelist-form input[name=_save]'); + // The button does not exist if no fields are editable. + if (el) { + el.addEventListener('click', function(event) { + if (document.querySelector('[name=action]').value) { + const text = list_editable_changed + ? gettext("You have selected an action, but you haven’t saved your changes to individual fields yet. Please click OK to save. You’ll need to re-run the action.") + : gettext("You have selected an action, and you haven’t made any changes on individual fields. You’re probably looking for the Go button rather than the Save button."); + if (!confirm(text)) { + event.preventDefault(); + } + } + }); + } + }; + + // Call function fn when the DOM is loaded and ready. If it is already + // loaded, call the function now. + // http://youmightnotneedjquery.com/#ready + function ready(fn) { + if (document.readyState !== 'loading') { + fn(); + } else { + document.addEventListener('DOMContentLoaded', fn); + } + } + + ready(function() { + const actionsEls = document.querySelectorAll('tr input.action-select'); + if (actionsEls.length > 0) { + Actions(actionsEls); + } + }); +} diff --git a/backend/week3/mydjangoproject/static/admin/js/admin/DateTimeShortcuts.js b/backend/week3/mydjangoproject/static/admin/js/admin/DateTimeShortcuts.js new file mode 100644 index 000000000..aa1cae9ee --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/admin/DateTimeShortcuts.js @@ -0,0 +1,408 @@ +/*global Calendar, findPosX, findPosY, get_format, gettext, gettext_noop, interpolate, ngettext, quickElement*/ +// Inserts shortcut buttons after all of the following: +// +// +'use strict'; +{ + const DateTimeShortcuts = { + calendars: [], + calendarInputs: [], + clockInputs: [], + clockHours: { + default_: [ + [gettext_noop('Now'), -1], + [gettext_noop('Midnight'), 0], + [gettext_noop('6 a.m.'), 6], + [gettext_noop('Noon'), 12], + [gettext_noop('6 p.m.'), 18] + ] + }, + dismissClockFunc: [], + dismissCalendarFunc: [], + calendarDivName1: 'calendarbox', // name of calendar
    that gets toggled + calendarDivName2: 'calendarin', // name of
    that contains calendar + calendarLinkName: 'calendarlink', // name of the link that is used to toggle + clockDivName: 'clockbox', // name of clock
    that gets toggled + clockLinkName: 'clocklink', // name of the link that is used to toggle + shortCutsClass: 'datetimeshortcuts', // class of the clock and cal shortcuts + timezoneWarningClass: 'timezonewarning', // class of the warning for timezone mismatch + timezoneOffset: 0, + init: function() { + const serverOffset = document.body.dataset.adminUtcOffset; + if (serverOffset) { + const localOffset = new Date().getTimezoneOffset() * -60; + DateTimeShortcuts.timezoneOffset = localOffset - serverOffset; + } + + for (const inp of document.getElementsByTagName('input')) { + if (inp.type === 'text' && inp.classList.contains('vTimeField')) { + DateTimeShortcuts.addClock(inp); + DateTimeShortcuts.addTimezoneWarning(inp); + } + else if (inp.type === 'text' && inp.classList.contains('vDateField')) { + DateTimeShortcuts.addCalendar(inp); + DateTimeShortcuts.addTimezoneWarning(inp); + } + } + }, + // Return the current time while accounting for the server timezone. + now: function() { + const serverOffset = document.body.dataset.adminUtcOffset; + if (serverOffset) { + const localNow = new Date(); + const localOffset = localNow.getTimezoneOffset() * -60; + localNow.setTime(localNow.getTime() + 1000 * (serverOffset - localOffset)); + return localNow; + } else { + return new Date(); + } + }, + // Add a warning when the time zone in the browser and backend do not match. + addTimezoneWarning: function(inp) { + const warningClass = DateTimeShortcuts.timezoneWarningClass; + let timezoneOffset = DateTimeShortcuts.timezoneOffset / 3600; + + // Only warn if there is a time zone mismatch. + if (!timezoneOffset) { + return; + } + + // Check if warning is already there. + if (inp.parentNode.querySelectorAll('.' + warningClass).length) { + return; + } + + let message; + if (timezoneOffset > 0) { + message = ngettext( + 'Note: You are %s hour ahead of server time.', + 'Note: You are %s hours ahead of server time.', + timezoneOffset + ); + } + else { + timezoneOffset *= -1; + message = ngettext( + 'Note: You are %s hour behind server time.', + 'Note: You are %s hours behind server time.', + timezoneOffset + ); + } + message = interpolate(message, [timezoneOffset]); + + const warning = document.createElement('div'); + warning.classList.add('help', warningClass); + warning.textContent = message; + inp.parentNode.appendChild(warning); + }, + // Add clock widget to a given field + addClock: function(inp) { + const num = DateTimeShortcuts.clockInputs.length; + DateTimeShortcuts.clockInputs[num] = inp; + DateTimeShortcuts.dismissClockFunc[num] = function() { DateTimeShortcuts.dismissClock(num); return true; }; + + // Shortcut links (clock icon and "Now" link) + const shortcuts_span = document.createElement('span'); + shortcuts_span.className = DateTimeShortcuts.shortCutsClass; + inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling); + const now_link = document.createElement('a'); + now_link.href = "#"; + now_link.textContent = gettext('Now'); + now_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleClockQuicklink(num, -1); + }); + const clock_link = document.createElement('a'); + clock_link.href = '#'; + clock_link.id = DateTimeShortcuts.clockLinkName + num; + clock_link.addEventListener('click', function(e) { + e.preventDefault(); + // avoid triggering the document click handler to dismiss the clock + e.stopPropagation(); + DateTimeShortcuts.openClock(num); + }); + + quickElement( + 'span', clock_link, '', + 'class', 'clock-icon', + 'title', gettext('Choose a Time') + ); + shortcuts_span.appendChild(document.createTextNode('\u00A0')); + shortcuts_span.appendChild(now_link); + shortcuts_span.appendChild(document.createTextNode('\u00A0|\u00A0')); + shortcuts_span.appendChild(clock_link); + + // Create clock link div + // + // Markup looks like: + //
    + //

    Choose a time

    + // + //

    Cancel

    + //
    + + const clock_box = document.createElement('div'); + clock_box.style.display = 'none'; + clock_box.style.position = 'absolute'; + clock_box.className = 'clockbox module'; + clock_box.id = DateTimeShortcuts.clockDivName + num; + document.body.appendChild(clock_box); + clock_box.addEventListener('click', function(e) { e.stopPropagation(); }); + + quickElement('h2', clock_box, gettext('Choose a time')); + const time_list = quickElement('ul', clock_box); + time_list.className = 'timelist'; + // The list of choices can be overridden in JavaScript like this: + // DateTimeShortcuts.clockHours.name = [['3 a.m.', 3]]; + // where name is the name attribute of the . + const name = typeof DateTimeShortcuts.clockHours[inp.name] === 'undefined' ? 'default_' : inp.name; + DateTimeShortcuts.clockHours[name].forEach(function(element) { + const time_link = quickElement('a', quickElement('li', time_list), gettext(element[0]), 'href', '#'); + time_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleClockQuicklink(num, element[1]); + }); + }); + + const cancel_p = quickElement('p', clock_box); + cancel_p.className = 'calendar-cancel'; + const cancel_link = quickElement('a', cancel_p, gettext('Cancel'), 'href', '#'); + cancel_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.dismissClock(num); + }); + + document.addEventListener('keyup', function(event) { + if (event.which === 27) { + // ESC key closes popup + DateTimeShortcuts.dismissClock(num); + event.preventDefault(); + } + }); + }, + openClock: function(num) { + const clock_box = document.getElementById(DateTimeShortcuts.clockDivName + num); + const clock_link = document.getElementById(DateTimeShortcuts.clockLinkName + num); + + // Recalculate the clockbox position + // is it left-to-right or right-to-left layout ? + if (window.getComputedStyle(document.body).direction !== 'rtl') { + clock_box.style.left = findPosX(clock_link) + 17 + 'px'; + } + else { + // since style's width is in em, it'd be tough to calculate + // px value of it. let's use an estimated px for now + clock_box.style.left = findPosX(clock_link) - 110 + 'px'; + } + clock_box.style.top = Math.max(0, findPosY(clock_link) - 30) + 'px'; + + // Show the clock box + clock_box.style.display = 'block'; + document.addEventListener('click', DateTimeShortcuts.dismissClockFunc[num]); + }, + dismissClock: function(num) { + document.getElementById(DateTimeShortcuts.clockDivName + num).style.display = 'none'; + document.removeEventListener('click', DateTimeShortcuts.dismissClockFunc[num]); + }, + handleClockQuicklink: function(num, val) { + let d; + if (val === -1) { + d = DateTimeShortcuts.now(); + } + else { + d = new Date(1970, 1, 1, val, 0, 0, 0); + } + DateTimeShortcuts.clockInputs[num].value = d.strftime(get_format('TIME_INPUT_FORMATS')[0]); + DateTimeShortcuts.clockInputs[num].focus(); + DateTimeShortcuts.dismissClock(num); + }, + // Add calendar widget to a given field. + addCalendar: function(inp) { + const num = DateTimeShortcuts.calendars.length; + + DateTimeShortcuts.calendarInputs[num] = inp; + DateTimeShortcuts.dismissCalendarFunc[num] = function() { DateTimeShortcuts.dismissCalendar(num); return true; }; + + // Shortcut links (calendar icon and "Today" link) + const shortcuts_span = document.createElement('span'); + shortcuts_span.className = DateTimeShortcuts.shortCutsClass; + inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling); + const today_link = document.createElement('a'); + today_link.href = '#'; + today_link.appendChild(document.createTextNode(gettext('Today'))); + today_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleCalendarQuickLink(num, 0); + }); + const cal_link = document.createElement('a'); + cal_link.href = '#'; + cal_link.id = DateTimeShortcuts.calendarLinkName + num; + cal_link.addEventListener('click', function(e) { + e.preventDefault(); + // avoid triggering the document click handler to dismiss the calendar + e.stopPropagation(); + DateTimeShortcuts.openCalendar(num); + }); + quickElement( + 'span', cal_link, '', + 'class', 'date-icon', + 'title', gettext('Choose a Date') + ); + shortcuts_span.appendChild(document.createTextNode('\u00A0')); + shortcuts_span.appendChild(today_link); + shortcuts_span.appendChild(document.createTextNode('\u00A0|\u00A0')); + shortcuts_span.appendChild(cal_link); + + // Create calendarbox div. + // + // Markup looks like: + // + //
    + //

    + // + // February 2003 + //

    + //
    + // + //
    + //
    + // Yesterday | Today | Tomorrow + //
    + //

    Cancel

    + //
    + const cal_box = document.createElement('div'); + cal_box.style.display = 'none'; + cal_box.style.position = 'absolute'; + cal_box.className = 'calendarbox module'; + cal_box.id = DateTimeShortcuts.calendarDivName1 + num; + document.body.appendChild(cal_box); + cal_box.addEventListener('click', function(e) { e.stopPropagation(); }); + + // next-prev links + const cal_nav = quickElement('div', cal_box); + const cal_nav_prev = quickElement('a', cal_nav, '<', 'href', '#'); + cal_nav_prev.className = 'calendarnav-previous'; + cal_nav_prev.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.drawPrev(num); + }); + + const cal_nav_next = quickElement('a', cal_nav, '>', 'href', '#'); + cal_nav_next.className = 'calendarnav-next'; + cal_nav_next.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.drawNext(num); + }); + + // main box + const cal_main = quickElement('div', cal_box, '', 'id', DateTimeShortcuts.calendarDivName2 + num); + cal_main.className = 'calendar'; + DateTimeShortcuts.calendars[num] = new Calendar(DateTimeShortcuts.calendarDivName2 + num, DateTimeShortcuts.handleCalendarCallback(num)); + DateTimeShortcuts.calendars[num].drawCurrent(); + + // calendar shortcuts + const shortcuts = quickElement('div', cal_box); + shortcuts.className = 'calendar-shortcuts'; + let day_link = quickElement('a', shortcuts, gettext('Yesterday'), 'href', '#'); + day_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleCalendarQuickLink(num, -1); + }); + shortcuts.appendChild(document.createTextNode('\u00A0|\u00A0')); + day_link = quickElement('a', shortcuts, gettext('Today'), 'href', '#'); + day_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleCalendarQuickLink(num, 0); + }); + shortcuts.appendChild(document.createTextNode('\u00A0|\u00A0')); + day_link = quickElement('a', shortcuts, gettext('Tomorrow'), 'href', '#'); + day_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.handleCalendarQuickLink(num, +1); + }); + + // cancel bar + const cancel_p = quickElement('p', cal_box); + cancel_p.className = 'calendar-cancel'; + const cancel_link = quickElement('a', cancel_p, gettext('Cancel'), 'href', '#'); + cancel_link.addEventListener('click', function(e) { + e.preventDefault(); + DateTimeShortcuts.dismissCalendar(num); + }); + document.addEventListener('keyup', function(event) { + if (event.which === 27) { + // ESC key closes popup + DateTimeShortcuts.dismissCalendar(num); + event.preventDefault(); + } + }); + }, + openCalendar: function(num) { + const cal_box = document.getElementById(DateTimeShortcuts.calendarDivName1 + num); + const cal_link = document.getElementById(DateTimeShortcuts.calendarLinkName + num); + const inp = DateTimeShortcuts.calendarInputs[num]; + + // Determine if the current value in the input has a valid date. + // If so, draw the calendar with that date's year and month. + if (inp.value) { + const format = get_format('DATE_INPUT_FORMATS')[0]; + const selected = inp.value.strptime(format); + const year = selected.getUTCFullYear(); + const month = selected.getUTCMonth() + 1; + const re = /\d{4}/; + if (re.test(year.toString()) && month >= 1 && month <= 12) { + DateTimeShortcuts.calendars[num].drawDate(month, year, selected); + } + } + + // Recalculate the clockbox position + // is it left-to-right or right-to-left layout ? + if (window.getComputedStyle(document.body).direction !== 'rtl') { + cal_box.style.left = findPosX(cal_link) + 17 + 'px'; + } + else { + // since style's width is in em, it'd be tough to calculate + // px value of it. let's use an estimated px for now + cal_box.style.left = findPosX(cal_link) - 180 + 'px'; + } + cal_box.style.top = Math.max(0, findPosY(cal_link) - 75) + 'px'; + + cal_box.style.display = 'block'; + document.addEventListener('click', DateTimeShortcuts.dismissCalendarFunc[num]); + }, + dismissCalendar: function(num) { + document.getElementById(DateTimeShortcuts.calendarDivName1 + num).style.display = 'none'; + document.removeEventListener('click', DateTimeShortcuts.dismissCalendarFunc[num]); + }, + drawPrev: function(num) { + DateTimeShortcuts.calendars[num].drawPreviousMonth(); + }, + drawNext: function(num) { + DateTimeShortcuts.calendars[num].drawNextMonth(); + }, + handleCalendarCallback: function(num) { + const format = get_format('DATE_INPUT_FORMATS')[0]; + return function(y, m, d) { + DateTimeShortcuts.calendarInputs[num].value = new Date(y, m - 1, d).strftime(format); + DateTimeShortcuts.calendarInputs[num].focus(); + document.getElementById(DateTimeShortcuts.calendarDivName1 + num).style.display = 'none'; + }; + }, + handleCalendarQuickLink: function(num, offset) { + const d = DateTimeShortcuts.now(); + d.setDate(d.getDate() + offset); + DateTimeShortcuts.calendarInputs[num].value = d.strftime(get_format('DATE_INPUT_FORMATS')[0]); + DateTimeShortcuts.calendarInputs[num].focus(); + DateTimeShortcuts.dismissCalendar(num); + } + }; + + window.addEventListener('load', DateTimeShortcuts.init); + window.DateTimeShortcuts = DateTimeShortcuts; +} diff --git a/backend/week3/mydjangoproject/static/admin/js/admin/RelatedObjectLookups.js b/backend/week3/mydjangoproject/static/admin/js/admin/RelatedObjectLookups.js new file mode 100644 index 000000000..afb6b66c2 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/admin/RelatedObjectLookups.js @@ -0,0 +1,238 @@ +/*global SelectBox, interpolate*/ +// Handles related-objects functionality: lookup link for raw_id_fields +// and Add Another links. +'use strict'; +{ + const $ = django.jQuery; + let popupIndex = 0; + const relatedWindows = []; + + function dismissChildPopups() { + relatedWindows.forEach(function(win) { + if(!win.closed) { + win.dismissChildPopups(); + win.close(); + } + }); + } + + function setPopupIndex() { + if(document.getElementsByName("_popup").length > 0) { + const index = window.name.lastIndexOf("__") + 2; + popupIndex = parseInt(window.name.substring(index)); + } else { + popupIndex = 0; + } + } + + function addPopupIndex(name) { + return name + "__" + (popupIndex + 1); + } + + function removePopupIndex(name) { + return name.replace(new RegExp("__" + (popupIndex + 1) + "$"), ''); + } + + function showAdminPopup(triggeringLink, name_regexp, add_popup) { + const name = addPopupIndex(triggeringLink.id.replace(name_regexp, '')); + const href = new URL(triggeringLink.href); + if (add_popup) { + href.searchParams.set('_popup', 1); + } + const win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes'); + relatedWindows.push(win); + win.focus(); + return false; + } + + function showRelatedObjectLookupPopup(triggeringLink) { + return showAdminPopup(triggeringLink, /^lookup_/, true); + } + + function dismissRelatedLookupPopup(win, chosenId) { + const name = removePopupIndex(win.name); + const elem = document.getElementById(name); + if (elem.classList.contains('vManyToManyRawIdAdminField') && elem.value) { + elem.value += ',' + chosenId; + } else { + document.getElementById(name).value = chosenId; + } + const index = relatedWindows.indexOf(win); + if (index > -1) { + relatedWindows.splice(index, 1); + } + win.close(); + } + + function showRelatedObjectPopup(triggeringLink) { + return showAdminPopup(triggeringLink, /^(change|add|delete)_/, false); + } + + function updateRelatedObjectLinks(triggeringLink) { + const $this = $(triggeringLink); + const siblings = $this.nextAll('.view-related, .change-related, .delete-related'); + if (!siblings.length) { + return; + } + const value = $this.val(); + if (value) { + siblings.each(function() { + const elm = $(this); + elm.attr('href', elm.attr('data-href-template').replace('__fk__', value)); + }); + } else { + siblings.removeAttr('href'); + } + } + + function updateRelatedSelectsOptions(currentSelect, win, objId, newRepr, newId) { + // After create/edit a model from the options next to the current + // select (+ or :pencil:) update ForeignKey PK of the rest of selects + // in the page. + + const path = win.location.pathname; + // Extract the model from the popup url '...//add/' or + // '...///change/' depending the action (add or change). + const modelName = path.split('/')[path.split('/').length - (objId ? 4 : 3)]; + // Exclude autocomplete selects. + const selectsRelated = document.querySelectorAll(`[data-model-ref="${modelName}"] select:not(.admin-autocomplete)`); + + selectsRelated.forEach(function(select) { + if (currentSelect === select) { + return; + } + + let option = select.querySelector(`option[value="${objId}"]`); + + if (!option) { + option = new Option(newRepr, newId); + select.options.add(option); + return; + } + + option.textContent = newRepr; + option.value = newId; + }); + } + + function dismissAddRelatedObjectPopup(win, newId, newRepr) { + const name = removePopupIndex(win.name); + const elem = document.getElementById(name); + if (elem) { + const elemName = elem.nodeName.toUpperCase(); + if (elemName === 'SELECT') { + elem.options[elem.options.length] = new Option(newRepr, newId, true, true); + updateRelatedSelectsOptions(elem, win, null, newRepr, newId); + } else if (elemName === 'INPUT') { + if (elem.classList.contains('vManyToManyRawIdAdminField') && elem.value) { + elem.value += ',' + newId; + } else { + elem.value = newId; + } + } + // Trigger a change event to update related links if required. + $(elem).trigger('change'); + } else { + const toId = name + "_to"; + const o = new Option(newRepr, newId); + SelectBox.add_to_cache(toId, o); + SelectBox.redisplay(toId); + } + const index = relatedWindows.indexOf(win); + if (index > -1) { + relatedWindows.splice(index, 1); + } + win.close(); + } + + function dismissChangeRelatedObjectPopup(win, objId, newRepr, newId) { + const id = removePopupIndex(win.name.replace(/^edit_/, '')); + const selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]); + const selects = $(selectsSelector); + selects.find('option').each(function() { + if (this.value === objId) { + this.textContent = newRepr; + this.value = newId; + } + }).trigger('change'); + updateRelatedSelectsOptions(selects[0], win, objId, newRepr, newId); + selects.next().find('.select2-selection__rendered').each(function() { + // The element can have a clear button as a child. + // Use the lastChild to modify only the displayed value. + this.lastChild.textContent = newRepr; + this.title = newRepr; + }); + const index = relatedWindows.indexOf(win); + if (index > -1) { + relatedWindows.splice(index, 1); + } + win.close(); + } + + function dismissDeleteRelatedObjectPopup(win, objId) { + const id = removePopupIndex(win.name.replace(/^delete_/, '')); + const selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]); + const selects = $(selectsSelector); + selects.find('option').each(function() { + if (this.value === objId) { + $(this).remove(); + } + }).trigger('change'); + const index = relatedWindows.indexOf(win); + if (index > -1) { + relatedWindows.splice(index, 1); + } + win.close(); + } + + window.showRelatedObjectLookupPopup = showRelatedObjectLookupPopup; + window.dismissRelatedLookupPopup = dismissRelatedLookupPopup; + window.showRelatedObjectPopup = showRelatedObjectPopup; + window.updateRelatedObjectLinks = updateRelatedObjectLinks; + window.dismissAddRelatedObjectPopup = dismissAddRelatedObjectPopup; + window.dismissChangeRelatedObjectPopup = dismissChangeRelatedObjectPopup; + window.dismissDeleteRelatedObjectPopup = dismissDeleteRelatedObjectPopup; + window.dismissChildPopups = dismissChildPopups; + + // Kept for backward compatibility + window.showAddAnotherPopup = showRelatedObjectPopup; + window.dismissAddAnotherPopup = dismissAddRelatedObjectPopup; + + window.addEventListener('unload', function(evt) { + window.dismissChildPopups(); + }); + + $(document).ready(function() { + setPopupIndex(); + $("a[data-popup-opener]").on('click', function(event) { + event.preventDefault(); + opener.dismissRelatedLookupPopup(window, $(this).data("popup-opener")); + }); + $('body').on('click', '.related-widget-wrapper-link[data-popup="yes"]', function(e) { + e.preventDefault(); + if (this.href) { + const event = $.Event('django:show-related', {href: this.href}); + $(this).trigger(event); + if (!event.isDefaultPrevented()) { + showRelatedObjectPopup(this); + } + } + }); + $('body').on('change', '.related-widget-wrapper select', function(e) { + const event = $.Event('django:update-related'); + $(this).trigger(event); + if (!event.isDefaultPrevented()) { + updateRelatedObjectLinks(this); + } + }); + $('.related-widget-wrapper select').trigger('change'); + $('body').on('click', '.related-lookup', function(e) { + e.preventDefault(); + const event = $.Event('django:lookup-related'); + $(this).trigger(event); + if (!event.isDefaultPrevented()) { + showRelatedObjectLookupPopup(this); + } + }); + }); +} diff --git a/backend/week3/mydjangoproject/static/admin/js/autocomplete.js b/backend/week3/mydjangoproject/static/admin/js/autocomplete.js new file mode 100644 index 000000000..d3daeab89 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/autocomplete.js @@ -0,0 +1,33 @@ +'use strict'; +{ + const $ = django.jQuery; + + $.fn.djangoAdminSelect2 = function() { + $.each(this, function(i, element) { + $(element).select2({ + ajax: { + data: (params) => { + return { + term: params.term, + page: params.page, + app_label: element.dataset.appLabel, + model_name: element.dataset.modelName, + field_name: element.dataset.fieldName + }; + } + } + }); + }); + return this; + }; + + $(function() { + // Initialize all autocomplete widgets except the one in the template + // form used when a new formset is added. + $('.admin-autocomplete').not('[name*=__prefix__]').djangoAdminSelect2(); + }); + + document.addEventListener('formset:added', (event) => { + $(event.target).find('.admin-autocomplete').djangoAdminSelect2(); + }); +} diff --git a/backend/week3/mydjangoproject/static/admin/js/calendar.js b/backend/week3/mydjangoproject/static/admin/js/calendar.js new file mode 100644 index 000000000..a62d10a75 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/calendar.js @@ -0,0 +1,221 @@ +/*global gettext, pgettext, get_format, quickElement, removeChildren*/ +/* +calendar.js - Calendar functions by Adrian Holovaty +depends on core.js for utility functions like removeChildren or quickElement +*/ +'use strict'; +{ + // CalendarNamespace -- Provides a collection of HTML calendar-related helper functions + const CalendarNamespace = { + monthsOfYear: [ + gettext('January'), + gettext('February'), + gettext('March'), + gettext('April'), + gettext('May'), + gettext('June'), + gettext('July'), + gettext('August'), + gettext('September'), + gettext('October'), + gettext('November'), + gettext('December') + ], + monthsOfYearAbbrev: [ + pgettext('abbrev. month January', 'Jan'), + pgettext('abbrev. month February', 'Feb'), + pgettext('abbrev. month March', 'Mar'), + pgettext('abbrev. month April', 'Apr'), + pgettext('abbrev. month May', 'May'), + pgettext('abbrev. month June', 'Jun'), + pgettext('abbrev. month July', 'Jul'), + pgettext('abbrev. month August', 'Aug'), + pgettext('abbrev. month September', 'Sep'), + pgettext('abbrev. month October', 'Oct'), + pgettext('abbrev. month November', 'Nov'), + pgettext('abbrev. month December', 'Dec') + ], + daysOfWeek: [ + pgettext('one letter Sunday', 'S'), + pgettext('one letter Monday', 'M'), + pgettext('one letter Tuesday', 'T'), + pgettext('one letter Wednesday', 'W'), + pgettext('one letter Thursday', 'T'), + pgettext('one letter Friday', 'F'), + pgettext('one letter Saturday', 'S') + ], + firstDayOfWeek: parseInt(get_format('FIRST_DAY_OF_WEEK')), + isLeapYear: function(year) { + return (((year % 4) === 0) && ((year % 100) !== 0 ) || ((year % 400) === 0)); + }, + getDaysInMonth: function(month, year) { + let days; + if (month === 1 || month === 3 || month === 5 || month === 7 || month === 8 || month === 10 || month === 12) { + days = 31; + } + else if (month === 4 || month === 6 || month === 9 || month === 11) { + days = 30; + } + else if (month === 2 && CalendarNamespace.isLeapYear(year)) { + days = 29; + } + else { + days = 28; + } + return days; + }, + draw: function(month, year, div_id, callback, selected) { // month = 1-12, year = 1-9999 + const today = new Date(); + const todayDay = today.getDate(); + const todayMonth = today.getMonth() + 1; + const todayYear = today.getFullYear(); + let todayClass = ''; + + // Use UTC functions here because the date field does not contain time + // and using the UTC function variants prevent the local time offset + // from altering the date, specifically the day field. For example: + // + // ``` + // var x = new Date('2013-10-02'); + // var day = x.getDate(); + // ``` + // + // The day variable above will be 1 instead of 2 in, say, US Pacific time + // zone. + let isSelectedMonth = false; + if (typeof selected !== 'undefined') { + isSelectedMonth = (selected.getUTCFullYear() === year && (selected.getUTCMonth() + 1) === month); + } + + month = parseInt(month); + year = parseInt(year); + const calDiv = document.getElementById(div_id); + removeChildren(calDiv); + const calTable = document.createElement('table'); + quickElement('caption', calTable, CalendarNamespace.monthsOfYear[month - 1] + ' ' + year); + const tableBody = quickElement('tbody', calTable); + + // Draw days-of-week header + let tableRow = quickElement('tr', tableBody); + for (let i = 0; i < 7; i++) { + quickElement('th', tableRow, CalendarNamespace.daysOfWeek[(i + CalendarNamespace.firstDayOfWeek) % 7]); + } + + const startingPos = new Date(year, month - 1, 1 - CalendarNamespace.firstDayOfWeek).getDay(); + const days = CalendarNamespace.getDaysInMonth(month, year); + + let nonDayCell; + + // Draw blanks before first of month + tableRow = quickElement('tr', tableBody); + for (let i = 0; i < startingPos; i++) { + nonDayCell = quickElement('td', tableRow, ' '); + nonDayCell.className = "nonday"; + } + + function calendarMonth(y, m) { + function onClick(e) { + e.preventDefault(); + callback(y, m, this.textContent); + } + return onClick; + } + + // Draw days of month + let currentDay = 1; + for (let i = startingPos; currentDay <= days; i++) { + if (i % 7 === 0 && currentDay !== 1) { + tableRow = quickElement('tr', tableBody); + } + if ((currentDay === todayDay) && (month === todayMonth) && (year === todayYear)) { + todayClass = 'today'; + } else { + todayClass = ''; + } + + // use UTC function; see above for explanation. + if (isSelectedMonth && currentDay === selected.getUTCDate()) { + if (todayClass !== '') { + todayClass += " "; + } + todayClass += "selected"; + } + + const cell = quickElement('td', tableRow, '', 'class', todayClass); + const link = quickElement('a', cell, currentDay, 'href', '#'); + link.addEventListener('click', calendarMonth(year, month)); + currentDay++; + } + + // Draw blanks after end of month (optional, but makes for valid code) + while (tableRow.childNodes.length < 7) { + nonDayCell = quickElement('td', tableRow, ' '); + nonDayCell.className = "nonday"; + } + + calDiv.appendChild(calTable); + } + }; + + // Calendar -- A calendar instance + function Calendar(div_id, callback, selected) { + // div_id (string) is the ID of the element in which the calendar will + // be displayed + // callback (string) is the name of a JavaScript function that will be + // called with the parameters (year, month, day) when a day in the + // calendar is clicked + this.div_id = div_id; + this.callback = callback; + this.today = new Date(); + this.currentMonth = this.today.getMonth() + 1; + this.currentYear = this.today.getFullYear(); + if (typeof selected !== 'undefined') { + this.selected = selected; + } + } + Calendar.prototype = { + drawCurrent: function() { + CalendarNamespace.draw(this.currentMonth, this.currentYear, this.div_id, this.callback, this.selected); + }, + drawDate: function(month, year, selected) { + this.currentMonth = month; + this.currentYear = year; + + if(selected) { + this.selected = selected; + } + + this.drawCurrent(); + }, + drawPreviousMonth: function() { + if (this.currentMonth === 1) { + this.currentMonth = 12; + this.currentYear--; + } + else { + this.currentMonth--; + } + this.drawCurrent(); + }, + drawNextMonth: function() { + if (this.currentMonth === 12) { + this.currentMonth = 1; + this.currentYear++; + } + else { + this.currentMonth++; + } + this.drawCurrent(); + }, + drawPreviousYear: function() { + this.currentYear--; + this.drawCurrent(); + }, + drawNextYear: function() { + this.currentYear++; + this.drawCurrent(); + } + }; + window.Calendar = Calendar; + window.CalendarNamespace = CalendarNamespace; +} diff --git a/backend/week3/mydjangoproject/static/admin/js/cancel.js b/backend/week3/mydjangoproject/static/admin/js/cancel.js new file mode 100644 index 000000000..3069c6f27 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/cancel.js @@ -0,0 +1,29 @@ +'use strict'; +{ + // Call function fn when the DOM is loaded and ready. If it is already + // loaded, call the function now. + // http://youmightnotneedjquery.com/#ready + function ready(fn) { + if (document.readyState !== 'loading') { + fn(); + } else { + document.addEventListener('DOMContentLoaded', fn); + } + } + + ready(function() { + function handleClick(event) { + event.preventDefault(); + const params = new URLSearchParams(window.location.search); + if (params.has('_popup')) { + window.close(); // Close the popup. + } else { + window.history.back(); // Otherwise, go back. + } + } + + document.querySelectorAll('.cancel-link').forEach(function(el) { + el.addEventListener('click', handleClick); + }); + }); +} diff --git a/backend/week3/mydjangoproject/static/admin/js/change_form.js b/backend/week3/mydjangoproject/static/admin/js/change_form.js new file mode 100644 index 000000000..96a4c62ef --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/change_form.js @@ -0,0 +1,16 @@ +'use strict'; +{ + const inputTags = ['BUTTON', 'INPUT', 'SELECT', 'TEXTAREA']; + const modelName = document.getElementById('django-admin-form-add-constants').dataset.modelName; + if (modelName) { + const form = document.getElementById(modelName + '_form'); + for (const element of form.elements) { + // HTMLElement.offsetParent returns null when the element is not + // rendered. + if (inputTags.includes(element.tagName) && !element.disabled && element.offsetParent) { + element.focus(); + break; + } + } + } +} diff --git a/backend/week3/mydjangoproject/static/admin/js/collapse.js b/backend/week3/mydjangoproject/static/admin/js/collapse.js new file mode 100644 index 000000000..c6c7b0f68 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/collapse.js @@ -0,0 +1,43 @@ +/*global gettext*/ +'use strict'; +{ + window.addEventListener('load', function() { + // Add anchor tag for Show/Hide link + const fieldsets = document.querySelectorAll('fieldset.collapse'); + for (const [i, elem] of fieldsets.entries()) { + // Don't hide if fields in this fieldset have errors + if (elem.querySelectorAll('div.errors, ul.errorlist').length === 0) { + elem.classList.add('collapsed'); + const h2 = elem.querySelector('h2'); + const link = document.createElement('a'); + link.id = 'fieldsetcollapser' + i; + link.className = 'collapse-toggle'; + link.href = '#'; + link.textContent = gettext('Show'); + h2.appendChild(document.createTextNode(' (')); + h2.appendChild(link); + h2.appendChild(document.createTextNode(')')); + } + } + // Add toggle to hide/show anchor tag + const toggleFunc = function(ev) { + if (ev.target.matches('.collapse-toggle')) { + ev.preventDefault(); + ev.stopPropagation(); + const fieldset = ev.target.closest('fieldset'); + if (fieldset.classList.contains('collapsed')) { + // Show + ev.target.textContent = gettext('Hide'); + fieldset.classList.remove('collapsed'); + } else { + // Hide + ev.target.textContent = gettext('Show'); + fieldset.classList.add('collapsed'); + } + } + }; + document.querySelectorAll('fieldset.module').forEach(function(el) { + el.addEventListener('click', toggleFunc); + }); + }); +} diff --git a/backend/week3/mydjangoproject/static/admin/js/core.js b/backend/week3/mydjangoproject/static/admin/js/core.js new file mode 100644 index 000000000..0344a13f4 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/core.js @@ -0,0 +1,170 @@ +// Core JavaScript helper functions +'use strict'; + +// quickElement(tagType, parentReference [, textInChildNode, attribute, attributeValue ...]); +function quickElement() { + const obj = document.createElement(arguments[0]); + if (arguments[2]) { + const textNode = document.createTextNode(arguments[2]); + obj.appendChild(textNode); + } + const len = arguments.length; + for (let i = 3; i < len; i += 2) { + obj.setAttribute(arguments[i], arguments[i + 1]); + } + arguments[1].appendChild(obj); + return obj; +} + +// "a" is reference to an object +function removeChildren(a) { + while (a.hasChildNodes()) { + a.removeChild(a.lastChild); + } +} + +// ---------------------------------------------------------------------------- +// Find-position functions by PPK +// See https://www.quirksmode.org/js/findpos.html +// ---------------------------------------------------------------------------- +function findPosX(obj) { + let curleft = 0; + if (obj.offsetParent) { + while (obj.offsetParent) { + curleft += obj.offsetLeft - obj.scrollLeft; + obj = obj.offsetParent; + } + } else if (obj.x) { + curleft += obj.x; + } + return curleft; +} + +function findPosY(obj) { + let curtop = 0; + if (obj.offsetParent) { + while (obj.offsetParent) { + curtop += obj.offsetTop - obj.scrollTop; + obj = obj.offsetParent; + } + } else if (obj.y) { + curtop += obj.y; + } + return curtop; +} + +//----------------------------------------------------------------------------- +// Date object extensions +// ---------------------------------------------------------------------------- +{ + Date.prototype.getTwelveHours = function() { + return this.getHours() % 12 || 12; + }; + + Date.prototype.getTwoDigitMonth = function() { + return (this.getMonth() < 9) ? '0' + (this.getMonth() + 1) : (this.getMonth() + 1); + }; + + Date.prototype.getTwoDigitDate = function() { + return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate(); + }; + + Date.prototype.getTwoDigitTwelveHour = function() { + return (this.getTwelveHours() < 10) ? '0' + this.getTwelveHours() : this.getTwelveHours(); + }; + + Date.prototype.getTwoDigitHour = function() { + return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours(); + }; + + Date.prototype.getTwoDigitMinute = function() { + return (this.getMinutes() < 10) ? '0' + this.getMinutes() : this.getMinutes(); + }; + + Date.prototype.getTwoDigitSecond = function() { + return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds(); + }; + + Date.prototype.getAbbrevMonthName = function() { + return typeof window.CalendarNamespace === "undefined" + ? this.getTwoDigitMonth() + : window.CalendarNamespace.monthsOfYearAbbrev[this.getMonth()]; + }; + + Date.prototype.getFullMonthName = function() { + return typeof window.CalendarNamespace === "undefined" + ? this.getTwoDigitMonth() + : window.CalendarNamespace.monthsOfYear[this.getMonth()]; + }; + + Date.prototype.strftime = function(format) { + const fields = { + b: this.getAbbrevMonthName(), + B: this.getFullMonthName(), + c: this.toString(), + d: this.getTwoDigitDate(), + H: this.getTwoDigitHour(), + I: this.getTwoDigitTwelveHour(), + m: this.getTwoDigitMonth(), + M: this.getTwoDigitMinute(), + p: (this.getHours() >= 12) ? 'PM' : 'AM', + S: this.getTwoDigitSecond(), + w: '0' + this.getDay(), + x: this.toLocaleDateString(), + X: this.toLocaleTimeString(), + y: ('' + this.getFullYear()).substr(2, 4), + Y: '' + this.getFullYear(), + '%': '%' + }; + let result = '', i = 0; + while (i < format.length) { + if (format.charAt(i) === '%') { + result += fields[format.charAt(i + 1)]; + ++i; + } + else { + result += format.charAt(i); + } + ++i; + } + return result; + }; + + // ---------------------------------------------------------------------------- + // String object extensions + // ---------------------------------------------------------------------------- + String.prototype.strptime = function(format) { + const split_format = format.split(/[.\-/]/); + const date = this.split(/[.\-/]/); + let i = 0; + let day, month, year; + while (i < split_format.length) { + switch (split_format[i]) { + case "%d": + day = date[i]; + break; + case "%m": + month = date[i] - 1; + break; + case "%Y": + year = date[i]; + break; + case "%y": + // A %y value in the range of [00, 68] is in the current + // century, while [69, 99] is in the previous century, + // according to the Open Group Specification. + if (parseInt(date[i], 10) >= 69) { + year = date[i]; + } else { + year = (new Date(Date.UTC(date[i], 0))).getUTCFullYear() + 100; + } + break; + } + ++i; + } + // Create Date object from UTC since the parsed value is supposed to be + // in UTC, not local time. Also, the calendar uses UTC functions for + // date extraction. + return new Date(Date.UTC(year, month, day)); + }; +} diff --git a/backend/week3/mydjangoproject/static/admin/js/filters.js b/backend/week3/mydjangoproject/static/admin/js/filters.js new file mode 100644 index 000000000..f5536ebc2 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/filters.js @@ -0,0 +1,30 @@ +/** + * Persist changelist filters state (collapsed/expanded). + */ +'use strict'; +{ + // Init filters. + let filters = JSON.parse(sessionStorage.getItem('django.admin.filtersState')); + + if (!filters) { + filters = {}; + } + + Object.entries(filters).forEach(([key, value]) => { + const detailElement = document.querySelector(`[data-filter-title='${CSS.escape(key)}']`); + + // Check if the filter is present, it could be from other view. + if (detailElement) { + value ? detailElement.setAttribute('open', '') : detailElement.removeAttribute('open'); + } + }); + + // Save filter state when clicks. + const details = document.querySelectorAll('details'); + details.forEach(detail => { + detail.addEventListener('toggle', event => { + filters[`${event.target.dataset.filterTitle}`] = detail.open; + sessionStorage.setItem('django.admin.filtersState', JSON.stringify(filters)); + }); + }); +} diff --git a/backend/week3/mydjangoproject/static/admin/js/inlines.js b/backend/week3/mydjangoproject/static/admin/js/inlines.js new file mode 100644 index 000000000..e9a1dfe12 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/inlines.js @@ -0,0 +1,359 @@ +/*global DateTimeShortcuts, SelectFilter*/ +/** + * Django admin inlines + * + * Based on jQuery Formset 1.1 + * @author Stanislaus Madueke (stan DOT madueke AT gmail DOT com) + * @requires jQuery 1.2.6 or later + * + * Copyright (c) 2009, Stanislaus Madueke + * All rights reserved. + * + * Spiced up with Code from Zain Memon's GSoC project 2009 + * and modified for Django by Jannis Leidel, Travis Swicegood and Julien Phalip. + * + * Licensed under the New BSD License + * See: https://opensource.org/licenses/bsd-license.php + */ +'use strict'; +{ + const $ = django.jQuery; + $.fn.formset = function(opts) { + const options = $.extend({}, $.fn.formset.defaults, opts); + const $this = $(this); + const $parent = $this.parent(); + const updateElementIndex = function(el, prefix, ndx) { + const id_regex = new RegExp("(" + prefix + "-(\\d+|__prefix__))"); + const replacement = prefix + "-" + ndx; + if ($(el).prop("for")) { + $(el).prop("for", $(el).prop("for").replace(id_regex, replacement)); + } + if (el.id) { + el.id = el.id.replace(id_regex, replacement); + } + if (el.name) { + el.name = el.name.replace(id_regex, replacement); + } + }; + const totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS").prop("autocomplete", "off"); + let nextIndex = parseInt(totalForms.val(), 10); + const maxForms = $("#id_" + options.prefix + "-MAX_NUM_FORMS").prop("autocomplete", "off"); + const minForms = $("#id_" + options.prefix + "-MIN_NUM_FORMS").prop("autocomplete", "off"); + let addButton; + + /** + * The "Add another MyModel" button below the inline forms. + */ + const addInlineAddButton = function() { + if (addButton === null) { + if ($this.prop("tagName") === "TR") { + // If forms are laid out as table rows, insert the + // "add" button in a new table row: + const numCols = $this.eq(-1).children().length; + $parent.append('' + options.addText + ""); + addButton = $parent.find("tr:last a"); + } else { + // Otherwise, insert it immediately after the last form: + $this.filter(":last").after('"); + addButton = $this.filter(":last").next().find("a"); + } + } + addButton.on('click', addInlineClickHandler); + }; + + const addInlineClickHandler = function(e) { + e.preventDefault(); + const template = $("#" + options.prefix + "-empty"); + const row = template.clone(true); + row.removeClass(options.emptyCssClass) + .addClass(options.formCssClass) + .attr("id", options.prefix + "-" + nextIndex); + addInlineDeleteButton(row); + row.find("*").each(function() { + updateElementIndex(this, options.prefix, totalForms.val()); + }); + // Insert the new form when it has been fully edited. + row.insertBefore($(template)); + // Update number of total forms. + $(totalForms).val(parseInt(totalForms.val(), 10) + 1); + nextIndex += 1; + // Hide the add button if there's a limit and it's been reached. + if ((maxForms.val() !== '') && (maxForms.val() - totalForms.val()) <= 0) { + addButton.parent().hide(); + } + // Show the remove buttons if there are more than min_num. + toggleDeleteButtonVisibility(row.closest('.inline-group')); + + // Pass the new form to the post-add callback, if provided. + if (options.added) { + options.added(row); + } + row.get(0).dispatchEvent(new CustomEvent("formset:added", { + bubbles: true, + detail: { + formsetName: options.prefix + } + })); + }; + + /** + * The "X" button that is part of every unsaved inline. + * (When saved, it is replaced with a "Delete" checkbox.) + */ + const addInlineDeleteButton = function(row) { + if (row.is("tr")) { + // If the forms are laid out in table rows, insert + // the remove button into the last table cell: + row.children(":last").append('"); + } else if (row.is("ul") || row.is("ol")) { + // If they're laid out as an ordered/unordered list, + // insert an
  • after the last list item: + row.append('
  • ' + options.deleteText + "
  • "); + } else { + // Otherwise, just insert the remove button as the + // last child element of the form's container: + row.children(":first").append('' + options.deleteText + ""); + } + // Add delete handler for each row. + row.find("a." + options.deleteCssClass).on('click', inlineDeleteHandler.bind(this)); + }; + + const inlineDeleteHandler = function(e1) { + e1.preventDefault(); + const deleteButton = $(e1.target); + const row = deleteButton.closest('.' + options.formCssClass); + const inlineGroup = row.closest('.inline-group'); + // Remove the parent form containing this button, + // and also remove the relevant row with non-field errors: + const prevRow = row.prev(); + if (prevRow.length && prevRow.hasClass('row-form-errors')) { + prevRow.remove(); + } + row.remove(); + nextIndex -= 1; + // Pass the deleted form to the post-delete callback, if provided. + if (options.removed) { + options.removed(row); + } + document.dispatchEvent(new CustomEvent("formset:removed", { + detail: { + formsetName: options.prefix + } + })); + // Update the TOTAL_FORMS form count. + const forms = $("." + options.formCssClass); + $("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length); + // Show add button again once below maximum number. + if ((maxForms.val() === '') || (maxForms.val() - forms.length) > 0) { + addButton.parent().show(); + } + // Hide the remove buttons if at min_num. + toggleDeleteButtonVisibility(inlineGroup); + // Also, update names and ids for all remaining form controls so + // they remain in sequence: + let i, formCount; + const updateElementCallback = function() { + updateElementIndex(this, options.prefix, i); + }; + for (i = 0, formCount = forms.length; i < formCount; i++) { + updateElementIndex($(forms).get(i), options.prefix, i); + $(forms.get(i)).find("*").each(updateElementCallback); + } + }; + + const toggleDeleteButtonVisibility = function(inlineGroup) { + if ((minForms.val() !== '') && (minForms.val() - totalForms.val()) >= 0) { + inlineGroup.find('.inline-deletelink').hide(); + } else { + inlineGroup.find('.inline-deletelink').show(); + } + }; + + $this.each(function(i) { + $(this).not("." + options.emptyCssClass).addClass(options.formCssClass); + }); + + // Create the delete buttons for all unsaved inlines: + $this.filter('.' + options.formCssClass + ':not(.has_original):not(.' + options.emptyCssClass + ')').each(function() { + addInlineDeleteButton($(this)); + }); + toggleDeleteButtonVisibility($this); + + // Create the add button, initially hidden. + addButton = options.addButton; + addInlineAddButton(); + + // Show the add button if allowed to add more items. + // Note that max_num = None translates to a blank string. + const showAddButton = maxForms.val() === '' || (maxForms.val() - totalForms.val()) > 0; + if ($this.length && showAddButton) { + addButton.parent().show(); + } else { + addButton.parent().hide(); + } + + return this; + }; + + /* Setup plugin defaults */ + $.fn.formset.defaults = { + prefix: "form", // The form prefix for your django formset + addText: "add another", // Text for the add link + deleteText: "remove", // Text for the delete link + addCssClass: "add-row", // CSS class applied to the add link + deleteCssClass: "delete-row", // CSS class applied to the delete link + emptyCssClass: "empty-row", // CSS class applied to the empty row + formCssClass: "dynamic-form", // CSS class applied to each form in a formset + added: null, // Function called each time a new form is added + removed: null, // Function called each time a form is deleted + addButton: null // Existing add button to use + }; + + + // Tabular inlines --------------------------------------------------------- + $.fn.tabularFormset = function(selector, options) { + const $rows = $(this); + + const reinitDateTimeShortCuts = function() { + // Reinitialize the calendar and clock widgets by force + if (typeof DateTimeShortcuts !== "undefined") { + $(".datetimeshortcuts").remove(); + DateTimeShortcuts.init(); + } + }; + + const updateSelectFilter = function() { + // If any SelectFilter widgets are a part of the new form, + // instantiate a new SelectFilter instance for it. + if (typeof SelectFilter !== 'undefined') { + $('.selectfilter').each(function(index, value) { + SelectFilter.init(value.id, this.dataset.fieldName, false); + }); + $('.selectfilterstacked').each(function(index, value) { + SelectFilter.init(value.id, this.dataset.fieldName, true); + }); + } + }; + + const initPrepopulatedFields = function(row) { + row.find('.prepopulated_field').each(function() { + const field = $(this), + input = field.find('input, select, textarea'), + dependency_list = input.data('dependency_list') || [], + dependencies = []; + $.each(dependency_list, function(i, field_name) { + dependencies.push('#' + row.find('.field-' + field_name).find('input, select, textarea').attr('id')); + }); + if (dependencies.length) { + input.prepopulate(dependencies, input.attr('maxlength')); + } + }); + }; + + $rows.formset({ + prefix: options.prefix, + addText: options.addText, + formCssClass: "dynamic-" + options.prefix, + deleteCssClass: "inline-deletelink", + deleteText: options.deleteText, + emptyCssClass: "empty-form", + added: function(row) { + initPrepopulatedFields(row); + reinitDateTimeShortCuts(); + updateSelectFilter(); + }, + addButton: options.addButton + }); + + return $rows; + }; + + // Stacked inlines --------------------------------------------------------- + $.fn.stackedFormset = function(selector, options) { + const $rows = $(this); + const updateInlineLabel = function(row) { + $(selector).find(".inline_label").each(function(i) { + const count = i + 1; + $(this).html($(this).html().replace(/(#\d+)/g, "#" + count)); + }); + }; + + const reinitDateTimeShortCuts = function() { + // Reinitialize the calendar and clock widgets by force, yuck. + if (typeof DateTimeShortcuts !== "undefined") { + $(".datetimeshortcuts").remove(); + DateTimeShortcuts.init(); + } + }; + + const updateSelectFilter = function() { + // If any SelectFilter widgets were added, instantiate a new instance. + if (typeof SelectFilter !== "undefined") { + $(".selectfilter").each(function(index, value) { + SelectFilter.init(value.id, this.dataset.fieldName, false); + }); + $(".selectfilterstacked").each(function(index, value) { + SelectFilter.init(value.id, this.dataset.fieldName, true); + }); + } + }; + + const initPrepopulatedFields = function(row) { + row.find('.prepopulated_field').each(function() { + const field = $(this), + input = field.find('input, select, textarea'), + dependency_list = input.data('dependency_list') || [], + dependencies = []; + $.each(dependency_list, function(i, field_name) { + // Dependency in a fieldset. + let field_element = row.find('.form-row .field-' + field_name); + // Dependency without a fieldset. + if (!field_element.length) { + field_element = row.find('.form-row.field-' + field_name); + } + dependencies.push('#' + field_element.find('input, select, textarea').attr('id')); + }); + if (dependencies.length) { + input.prepopulate(dependencies, input.attr('maxlength')); + } + }); + }; + + $rows.formset({ + prefix: options.prefix, + addText: options.addText, + formCssClass: "dynamic-" + options.prefix, + deleteCssClass: "inline-deletelink", + deleteText: options.deleteText, + emptyCssClass: "empty-form", + removed: updateInlineLabel, + added: function(row) { + initPrepopulatedFields(row); + reinitDateTimeShortCuts(); + updateSelectFilter(); + updateInlineLabel(row); + }, + addButton: options.addButton + }); + + return $rows; + }; + + $(document).ready(function() { + $(".js-inline-admin-formset").each(function() { + const data = $(this).data(), + inlineOptions = data.inlineFormset; + let selector; + switch(data.inlineType) { + case "stacked": + selector = inlineOptions.name + "-group .inline-related"; + $(selector).stackedFormset(selector, inlineOptions.options); + break; + case "tabular": + selector = inlineOptions.name + "-group .tabular.inline-related tbody:first > tr.form-row"; + $(selector).tabularFormset(selector, inlineOptions.options); + break; + } + }); + }); +} diff --git a/backend/week3/mydjangoproject/static/admin/js/jquery.init.js b/backend/week3/mydjangoproject/static/admin/js/jquery.init.js new file mode 100644 index 000000000..f40b27f47 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/jquery.init.js @@ -0,0 +1,8 @@ +/*global jQuery:false*/ +'use strict'; +/* Puts the included jQuery into our own namespace using noConflict and passing + * it 'true'. This ensures that the included jQuery doesn't pollute the global + * namespace (i.e. this preserves pre-existing values for both window.$ and + * window.jQuery). + */ +window.django = {jQuery: jQuery.noConflict(true)}; diff --git a/backend/week3/mydjangoproject/static/admin/js/nav_sidebar.js b/backend/week3/mydjangoproject/static/admin/js/nav_sidebar.js new file mode 100644 index 000000000..7e735db15 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/nav_sidebar.js @@ -0,0 +1,79 @@ +'use strict'; +{ + const toggleNavSidebar = document.getElementById('toggle-nav-sidebar'); + if (toggleNavSidebar !== null) { + const navSidebar = document.getElementById('nav-sidebar'); + const main = document.getElementById('main'); + let navSidebarIsOpen = localStorage.getItem('django.admin.navSidebarIsOpen'); + if (navSidebarIsOpen === null) { + navSidebarIsOpen = 'true'; + } + main.classList.toggle('shifted', navSidebarIsOpen === 'true'); + navSidebar.setAttribute('aria-expanded', navSidebarIsOpen); + + toggleNavSidebar.addEventListener('click', function() { + if (navSidebarIsOpen === 'true') { + navSidebarIsOpen = 'false'; + } else { + navSidebarIsOpen = 'true'; + } + localStorage.setItem('django.admin.navSidebarIsOpen', navSidebarIsOpen); + main.classList.toggle('shifted'); + navSidebar.setAttribute('aria-expanded', navSidebarIsOpen); + }); + } + + function initSidebarQuickFilter() { + const options = []; + const navSidebar = document.getElementById('nav-sidebar'); + if (!navSidebar) { + return; + } + navSidebar.querySelectorAll('th[scope=row] a').forEach((container) => { + options.push({title: container.innerHTML, node: container}); + }); + + function checkValue(event) { + let filterValue = event.target.value; + if (filterValue) { + filterValue = filterValue.toLowerCase(); + } + if (event.key === 'Escape') { + filterValue = ''; + event.target.value = ''; // clear input + } + let matches = false; + for (const o of options) { + let displayValue = ''; + if (filterValue) { + if (o.title.toLowerCase().indexOf(filterValue) === -1) { + displayValue = 'none'; + } else { + matches = true; + } + } + // show/hide parent + o.node.parentNode.parentNode.style.display = displayValue; + } + if (!filterValue || matches) { + event.target.classList.remove('no-results'); + } else { + event.target.classList.add('no-results'); + } + sessionStorage.setItem('django.admin.navSidebarFilterValue', filterValue); + } + + const nav = document.getElementById('nav-filter'); + nav.addEventListener('change', checkValue, false); + nav.addEventListener('input', checkValue, false); + nav.addEventListener('keyup', checkValue, false); + + const storedValue = sessionStorage.getItem('django.admin.navSidebarFilterValue'); + if (storedValue) { + nav.value = storedValue; + checkValue({target: nav, key: ''}); + } + } + window.initSidebarQuickFilter = initSidebarQuickFilter; + initSidebarQuickFilter(); +} diff --git a/backend/week3/mydjangoproject/static/admin/js/popup_response.js b/backend/week3/mydjangoproject/static/admin/js/popup_response.js new file mode 100644 index 000000000..2b1d3dd31 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/popup_response.js @@ -0,0 +1,16 @@ +/*global opener */ +'use strict'; +{ + const initData = JSON.parse(document.getElementById('django-admin-popup-response-constants').dataset.popupResponse); + switch(initData.action) { + case 'change': + opener.dismissChangeRelatedObjectPopup(window, initData.value, initData.obj, initData.new_value); + break; + case 'delete': + opener.dismissDeleteRelatedObjectPopup(window, initData.value); + break; + default: + opener.dismissAddRelatedObjectPopup(window, initData.value, initData.obj); + break; + } +} diff --git a/backend/week3/mydjangoproject/static/admin/js/prepopulate.js b/backend/week3/mydjangoproject/static/admin/js/prepopulate.js new file mode 100644 index 000000000..89e95ab44 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/prepopulate.js @@ -0,0 +1,43 @@ +/*global URLify*/ +'use strict'; +{ + const $ = django.jQuery; + $.fn.prepopulate = function(dependencies, maxLength, allowUnicode) { + /* + Depends on urlify.js + Populates a selected field with the values of the dependent fields, + URLifies and shortens the string. + dependencies - array of dependent fields ids + maxLength - maximum length of the URLify'd string + allowUnicode - Unicode support of the URLify'd string + */ + return this.each(function() { + const prepopulatedField = $(this); + + const populate = function() { + // Bail if the field's value has been changed by the user + if (prepopulatedField.data('_changed')) { + return; + } + + const values = []; + $.each(dependencies, function(i, field) { + field = $(field); + if (field.val().length > 0) { + values.push(field.val()); + } + }); + prepopulatedField.val(URLify(values.join(' '), maxLength, allowUnicode)); + }; + + prepopulatedField.data('_changed', false); + prepopulatedField.on('change', function() { + prepopulatedField.data('_changed', true); + }); + + if (!prepopulatedField.val()) { + $(dependencies.join(',')).on('keyup change focus', populate); + } + }); + }; +} diff --git a/backend/week3/mydjangoproject/static/admin/js/prepopulate_init.js b/backend/week3/mydjangoproject/static/admin/js/prepopulate_init.js new file mode 100644 index 000000000..a58841f00 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/prepopulate_init.js @@ -0,0 +1,15 @@ +'use strict'; +{ + const $ = django.jQuery; + const fields = $('#django-admin-prepopulated-fields-constants').data('prepopulatedFields'); + $.each(fields, function(index, field) { + $( + '.empty-form .form-row .field-' + field.name + + ', .empty-form.form-row .field-' + field.name + + ', .empty-form .form-row.field-' + field.name + ).addClass('prepopulated_field'); + $(field.id).data('dependency_list', field.dependency_list).prepopulate( + field.dependency_ids, field.maxLength, field.allowUnicode + ); + }); +} diff --git a/backend/week3/mydjangoproject/static/admin/js/theme.js b/backend/week3/mydjangoproject/static/admin/js/theme.js new file mode 100644 index 000000000..794cd15f7 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/theme.js @@ -0,0 +1,56 @@ +'use strict'; +{ + window.addEventListener('load', function(e) { + + function setTheme(mode) { + if (mode !== "light" && mode !== "dark" && mode !== "auto") { + console.error(`Got invalid theme mode: ${mode}. Resetting to auto.`); + mode = "auto"; + } + document.documentElement.dataset.theme = mode; + localStorage.setItem("theme", mode); + } + + function cycleTheme() { + const currentTheme = localStorage.getItem("theme") || "auto"; + const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches; + + if (prefersDark) { + // Auto (dark) -> Light -> Dark + if (currentTheme === "auto") { + setTheme("light"); + } else if (currentTheme === "light") { + setTheme("dark"); + } else { + setTheme("auto"); + } + } else { + // Auto (light) -> Dark -> Light + if (currentTheme === "auto") { + setTheme("dark"); + } else if (currentTheme === "dark") { + setTheme("light"); + } else { + setTheme("auto"); + } + } + } + + function initTheme() { + // set theme defined in localStorage if there is one, or fallback to auto mode + const currentTheme = localStorage.getItem("theme"); + currentTheme ? setTheme(currentTheme) : setTheme("auto"); + } + + function setupTheme() { + // Attach event handlers for toggling themes + const buttons = document.getElementsByClassName("theme-toggle"); + Array.from(buttons).forEach((btn) => { + btn.addEventListener("click", cycleTheme); + }); + initTheme(); + } + + setupTheme(); + }); +} diff --git a/backend/week3/mydjangoproject/static/admin/js/urlify.js b/backend/week3/mydjangoproject/static/admin/js/urlify.js new file mode 100644 index 000000000..9fc040949 --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/urlify.js @@ -0,0 +1,169 @@ +/*global XRegExp*/ +'use strict'; +{ + const LATIN_MAP = { + 'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE', + 'Ç': 'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I', + 'Î': 'I', 'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O', + 'Õ': 'O', 'Ö': 'O', 'Ő': 'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U', + 'Ü': 'U', 'Ű': 'U', 'Ý': 'Y', 'Þ': 'TH', 'Ÿ': 'Y', 'ß': 'ss', 'à': 'a', + 'á': 'a', 'â': 'a', 'ã': 'a', 'ä': 'a', 'å': 'a', 'æ': 'ae', 'ç': 'c', + 'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e', 'ì': 'i', 'í': 'i', 'î': 'i', + 'ï': 'i', 'ð': 'd', 'ñ': 'n', 'ò': 'o', 'ó': 'o', 'ô': 'o', 'õ': 'o', + 'ö': 'o', 'ő': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u', 'û': 'u', 'ü': 'u', + 'ű': 'u', 'ý': 'y', 'þ': 'th', 'ÿ': 'y' + }; + const LATIN_SYMBOLS_MAP = { + '©': '(c)' + }; + const GREEK_MAP = { + 'α': 'a', 'β': 'b', 'γ': 'g', 'δ': 'd', 'ε': 'e', 'ζ': 'z', 'η': 'h', + 'θ': '8', 'ι': 'i', 'κ': 'k', 'λ': 'l', 'μ': 'm', 'ν': 'n', 'ξ': '3', + 'ο': 'o', 'π': 'p', 'ρ': 'r', 'σ': 's', 'τ': 't', 'υ': 'y', 'φ': 'f', + 'χ': 'x', 'ψ': 'ps', 'ω': 'w', 'ά': 'a', 'έ': 'e', 'ί': 'i', 'ό': 'o', + 'ύ': 'y', 'ή': 'h', 'ώ': 'w', 'ς': 's', 'ϊ': 'i', 'ΰ': 'y', 'ϋ': 'y', + 'ΐ': 'i', 'Α': 'A', 'Β': 'B', 'Γ': 'G', 'Δ': 'D', 'Ε': 'E', 'Ζ': 'Z', + 'Η': 'H', 'Θ': '8', 'Ι': 'I', 'Κ': 'K', 'Λ': 'L', 'Μ': 'M', 'Ν': 'N', + 'Ξ': '3', 'Ο': 'O', 'Π': 'P', 'Ρ': 'R', 'Σ': 'S', 'Τ': 'T', 'Υ': 'Y', + 'Φ': 'F', 'Χ': 'X', 'Ψ': 'PS', 'Ω': 'W', 'Ά': 'A', 'Έ': 'E', 'Ί': 'I', + 'Ό': 'O', 'Ύ': 'Y', 'Ή': 'H', 'Ώ': 'W', 'Ϊ': 'I', 'Ϋ': 'Y' + }; + const TURKISH_MAP = { + 'ş': 's', 'Ş': 'S', 'ı': 'i', 'İ': 'I', 'ç': 'c', 'Ç': 'C', 'ü': 'u', + 'Ü': 'U', 'ö': 'o', 'Ö': 'O', 'ğ': 'g', 'Ğ': 'G' + }; + const ROMANIAN_MAP = { + 'ă': 'a', 'î': 'i', 'ș': 's', 'ț': 't', 'â': 'a', + 'Ă': 'A', 'Î': 'I', 'Ș': 'S', 'Ț': 'T', 'Â': 'A' + }; + const RUSSIAN_MAP = { + 'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'е': 'e', 'ё': 'yo', + 'ж': 'zh', 'з': 'z', 'и': 'i', 'й': 'j', 'к': 'k', 'л': 'l', 'м': 'm', + 'н': 'n', 'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't', 'у': 'u', + 'ф': 'f', 'х': 'h', 'ц': 'c', 'ч': 'ch', 'ш': 'sh', 'щ': 'sh', 'ъ': '', + 'ы': 'y', 'ь': '', 'э': 'e', 'ю': 'yu', 'я': 'ya', + 'А': 'A', 'Б': 'B', 'В': 'V', 'Г': 'G', 'Д': 'D', 'Е': 'E', 'Ё': 'Yo', + 'Ж': 'Zh', 'З': 'Z', 'И': 'I', 'Й': 'J', 'К': 'K', 'Л': 'L', 'М': 'M', + 'Н': 'N', 'О': 'O', 'П': 'P', 'Р': 'R', 'С': 'S', 'Т': 'T', 'У': 'U', + 'Ф': 'F', 'Х': 'H', 'Ц': 'C', 'Ч': 'Ch', 'Ш': 'Sh', 'Щ': 'Sh', 'Ъ': '', + 'Ы': 'Y', 'Ь': '', 'Э': 'E', 'Ю': 'Yu', 'Я': 'Ya' + }; + const UKRAINIAN_MAP = { + 'Є': 'Ye', 'І': 'I', 'Ї': 'Yi', 'Ґ': 'G', 'є': 'ye', 'і': 'i', + 'ї': 'yi', 'ґ': 'g' + }; + const CZECH_MAP = { + 'č': 'c', 'ď': 'd', 'ě': 'e', 'ň': 'n', 'ř': 'r', 'š': 's', 'ť': 't', + 'ů': 'u', 'ž': 'z', 'Č': 'C', 'Ď': 'D', 'Ě': 'E', 'Ň': 'N', 'Ř': 'R', + 'Š': 'S', 'Ť': 'T', 'Ů': 'U', 'Ž': 'Z' + }; + const SLOVAK_MAP = { + 'á': 'a', 'ä': 'a', 'č': 'c', 'ď': 'd', 'é': 'e', 'í': 'i', 'ľ': 'l', + 'ĺ': 'l', 'ň': 'n', 'ó': 'o', 'ô': 'o', 'ŕ': 'r', 'š': 's', 'ť': 't', + 'ú': 'u', 'ý': 'y', 'ž': 'z', + 'Á': 'a', 'Ä': 'A', 'Č': 'C', 'Ď': 'D', 'É': 'E', 'Í': 'I', 'Ľ': 'L', + 'Ĺ': 'L', 'Ň': 'N', 'Ó': 'O', 'Ô': 'O', 'Ŕ': 'R', 'Š': 'S', 'Ť': 'T', + 'Ú': 'U', 'Ý': 'Y', 'Ž': 'Z' + }; + const POLISH_MAP = { + 'ą': 'a', 'ć': 'c', 'ę': 'e', 'ł': 'l', 'ń': 'n', 'ó': 'o', 'ś': 's', + 'ź': 'z', 'ż': 'z', + 'Ą': 'A', 'Ć': 'C', 'Ę': 'E', 'Ł': 'L', 'Ń': 'N', 'Ó': 'O', 'Ś': 'S', + 'Ź': 'Z', 'Ż': 'Z' + }; + const LATVIAN_MAP = { + 'ā': 'a', 'č': 'c', 'ē': 'e', 'ģ': 'g', 'ī': 'i', 'ķ': 'k', 'ļ': 'l', + 'ņ': 'n', 'š': 's', 'ū': 'u', 'ž': 'z', + 'Ā': 'A', 'Č': 'C', 'Ē': 'E', 'Ģ': 'G', 'Ī': 'I', 'Ķ': 'K', 'Ļ': 'L', + 'Ņ': 'N', 'Š': 'S', 'Ū': 'U', 'Ž': 'Z' + }; + const ARABIC_MAP = { + 'أ': 'a', 'ب': 'b', 'ت': 't', 'ث': 'th', 'ج': 'g', 'ح': 'h', 'خ': 'kh', 'د': 'd', + 'ذ': 'th', 'ر': 'r', 'ز': 'z', 'س': 's', 'ش': 'sh', 'ص': 's', 'ض': 'd', 'ط': 't', + 'ظ': 'th', 'ع': 'aa', 'غ': 'gh', 'ف': 'f', 'ق': 'k', 'ك': 'k', 'ل': 'l', 'م': 'm', + 'ن': 'n', 'ه': 'h', 'و': 'o', 'ي': 'y' + }; + const LITHUANIAN_MAP = { + 'ą': 'a', 'č': 'c', 'ę': 'e', 'ė': 'e', 'į': 'i', 'š': 's', 'ų': 'u', + 'ū': 'u', 'ž': 'z', + 'Ą': 'A', 'Č': 'C', 'Ę': 'E', 'Ė': 'E', 'Į': 'I', 'Š': 'S', 'Ų': 'U', + 'Ū': 'U', 'Ž': 'Z' + }; + const SERBIAN_MAP = { + 'ђ': 'dj', 'ј': 'j', 'љ': 'lj', 'њ': 'nj', 'ћ': 'c', 'џ': 'dz', + 'đ': 'dj', 'Ђ': 'Dj', 'Ј': 'j', 'Љ': 'Lj', 'Њ': 'Nj', 'Ћ': 'C', + 'Џ': 'Dz', 'Đ': 'Dj' + }; + const AZERBAIJANI_MAP = { + 'ç': 'c', 'ə': 'e', 'ğ': 'g', 'ı': 'i', 'ö': 'o', 'ş': 's', 'ü': 'u', + 'Ç': 'C', 'Ə': 'E', 'Ğ': 'G', 'İ': 'I', 'Ö': 'O', 'Ş': 'S', 'Ü': 'U' + }; + const GEORGIAN_MAP = { + 'ა': 'a', 'ბ': 'b', 'გ': 'g', 'დ': 'd', 'ე': 'e', 'ვ': 'v', 'ზ': 'z', + 'თ': 't', 'ი': 'i', 'კ': 'k', 'ლ': 'l', 'მ': 'm', 'ნ': 'n', 'ო': 'o', + 'პ': 'p', 'ჟ': 'j', 'რ': 'r', 'ს': 's', 'ტ': 't', 'უ': 'u', 'ფ': 'f', + 'ქ': 'q', 'ღ': 'g', 'ყ': 'y', 'შ': 'sh', 'ჩ': 'ch', 'ც': 'c', 'ძ': 'dz', + 'წ': 'w', 'ჭ': 'ch', 'ხ': 'x', 'ჯ': 'j', 'ჰ': 'h' + }; + + const ALL_DOWNCODE_MAPS = [ + LATIN_MAP, + LATIN_SYMBOLS_MAP, + GREEK_MAP, + TURKISH_MAP, + ROMANIAN_MAP, + RUSSIAN_MAP, + UKRAINIAN_MAP, + CZECH_MAP, + SLOVAK_MAP, + POLISH_MAP, + LATVIAN_MAP, + ARABIC_MAP, + LITHUANIAN_MAP, + SERBIAN_MAP, + AZERBAIJANI_MAP, + GEORGIAN_MAP + ]; + + const Downcoder = { + 'Initialize': function() { + if (Downcoder.map) { // already made + return; + } + Downcoder.map = {}; + for (const lookup of ALL_DOWNCODE_MAPS) { + Object.assign(Downcoder.map, lookup); + } + Downcoder.regex = new RegExp(Object.keys(Downcoder.map).join('|'), 'g'); + } + }; + + function downcode(slug) { + Downcoder.Initialize(); + return slug.replace(Downcoder.regex, function(m) { + return Downcoder.map[m]; + }); + } + + + function URLify(s, num_chars, allowUnicode) { + // changes, e.g., "Petty theft" to "petty-theft" + if (!allowUnicode) { + s = downcode(s); + } + s = s.toLowerCase(); // convert to lowercase + // if downcode doesn't hit, the char will be stripped here + if (allowUnicode) { + // Keep Unicode letters including both lowercase and uppercase + // characters, whitespace, and dash; remove other characters. + s = XRegExp.replace(s, XRegExp('[^-_\\p{L}\\p{N}\\s]', 'g'), ''); + } else { + s = s.replace(/[^-\w\s]/g, ''); // remove unneeded chars + } + s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces + s = s.replace(/[-\s]+/g, '-'); // convert spaces to hyphens + s = s.substring(0, num_chars); // trim to first num_chars chars + return s.replace(/-+$/g, ''); // trim any trailing hyphens + } + window.URLify = URLify; +} diff --git a/backend/week3/mydjangoproject/static/admin/js/vendor/jquery/LICENSE.txt b/backend/week3/mydjangoproject/static/admin/js/vendor/jquery/LICENSE.txt new file mode 100644 index 000000000..f642c3f7a --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/vendor/jquery/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright OpenJS Foundation and other contributors, https://openjsf.org/ + +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. diff --git a/backend/week3/mydjangoproject/static/admin/js/vendor/jquery/jquery.js b/backend/week3/mydjangoproject/static/admin/js/vendor/jquery/jquery.js new file mode 100644 index 000000000..7f35c11bd --- /dev/null +++ b/backend/week3/mydjangoproject/static/admin/js/vendor/jquery/jquery.js @@ -0,0 +1,10965 @@ +/*! + * jQuery JavaScript Library v3.6.4 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2023-03-08T15:28Z + */ +( function( global, factory ) { + + "use strict"; + + 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 have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket trac-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 ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 + // Plus for old WebKit, typeof returns "function" for HTML collections + // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) + return typeof obj === "function" && typeof obj.nodeType !== "number" && + typeof obj.item !== "function"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.6.4", + + // 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 ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // 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 all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // 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; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + 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 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + 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(); + }, + + // 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" && !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 ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // 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() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // 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 ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + 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 length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + 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 flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), + function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.10 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2023-02-14 + */ +( 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" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ 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 + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // 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 + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rleadingCombinator = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "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" ) + }, + + rhtml = /HTML$/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 = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.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 m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rleadingCombinator.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + 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 element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = 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 = arr.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 && + a.sourceIndex - b.sourceIndex; + + // 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 :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * 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 !== "undefined" && 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 ) { + var namespace = elem && elem.namespaceURI, + docElem = elem && ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * 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, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + // Support: Chrome 105 - 110+, Safari 15.4 - 16.3+ + // Make sure the the `:has()` argument is parsed unforgivingly. + // We include `*` in the test to detect buggy implementations that are + // _selectively_ forgiving (specifically when the list includes at least + // one valid selector). + // Note that we treat complete lack of support for `:has()` as if it were + // spec-compliant support, which is fine because use of `:has()` in such + // environments will fail in the qSA path and fall back to jQuery traversal + // anyway. + support.cssHas = assert( function() { + try { + document.querySelector( ":has(*,:jqfake)" ); + return false; + } catch ( e ) { + return true; + } + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + 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 !== "undefined" && 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 https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // 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 + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).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 + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // 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 ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.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 ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + if ( !support.cssHas ) { + + // Support: Chrome 105 - 110+, Safari 15.4 - 16.3+ + // Our regular `try-catch` mechanism fails to detect natively-unsupported + // pseudo-classes inside `:has()` (such as `:has(:contains("Foo"))`) + // in browsers that parse the `:has()` argument as a forgiving selector list. + // https://drafts.csswg.org/selectors/#relational now requires the argument + // to be parsed unforgivingly, but browsers have not yet fully adjusted. + rbuggyQSA.push( ":has" ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + + // Support: IE <9 only + // IE doesn't have `contains` on `document` so we need to check for + // `documentElement` presence. + // We need to fall back to `a` when `documentElement` is missing + // as `ownerDocument` of elements within `