├── .gitignore ├── LICENSE ├── README.md ├── docs ├── images │ ├── body-bg.jpg │ ├── download-button.png │ ├── github-button.png │ ├── header-bg.jpg │ ├── highlight-bg.jpg │ └── sidebar-bg.jpg ├── javascripts │ └── main.js └── stylesheets │ ├── github-light.css │ ├── print.css │ └── stylesheet.css ├── examples ├── LivePreview │ └── AutocompleteTextbox │ │ ├── Autocomplete-Textbox.unity3d │ │ ├── UnityObject2.js │ │ ├── index.html │ │ └── jquery.min.js └── Localwire.UnityUIComponents.Examples │ ├── Assets │ ├── DLLs │ │ └── Localwire.UnityUIComponents.dll │ ├── JsonLocationsSource.cs │ ├── JsonLocationsWebSource.cs │ ├── LocationsAutocomplete.cs │ ├── Models │ │ └── Location.cs │ ├── Resources │ │ └── cities_testdata.json │ └── TestScene.unity │ ├── Localwire.UnityUIComponents.Examples.CSharp.csproj │ ├── Localwire.UnityUIComponents.Examples.sln │ └── ProjectSettings │ ├── AudioManager.asset │ ├── ClusterInputManager.asset │ ├── DynamicsManager.asset │ ├── EditorBuildSettings.asset │ ├── EditorSettings.asset │ ├── GraphicsSettings.asset │ ├── InputManager.asset │ ├── NavMeshAreas.asset │ ├── NetworkManager.asset │ ├── Physics2DSettings.asset │ ├── ProjectSettings.asset │ ├── ProjectVersion.txt │ ├── QualitySettings.asset │ ├── TagManager.asset │ ├── TimeManager.asset │ ├── UnityAdsSettings.asset │ └── UnityConnectSettings.asset ├── index.html ├── params.json └── src ├── Localwire.UnityUIComponents.sln └── Localwire.UnityUIComponents ├── AutocompleteTextbox ├── AutocompleteTextboxView.cs ├── SourceProvider │ └── IAutocompleteSourceProvider.cs └── Subelements │ └── AutocompleteResultListElement.cs ├── Localwire.UnityUIComponents.csproj ├── Properties └── AssemblyInfo.cs └── Shared └── UIExtensions.cs /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | examples/Localwire.UnityUIComponents.Examples/Library/ 254 | examples/Localwire.UnityUIComponents.Examples/Temp/ 255 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Michał Wilczyński 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UnityUIComponents 2 | Custom UI components for Unity3D game engine. Intended to fill the gap of some missing, yet useful UI components. 3 | 4 | ## Getting started 5 | 6 | You have two options to use UnityUIComponents in your project: 7 | * download repository, launch **/src/Localwire.UnityUIComponents.sln** and build project in **Release** mode, then copy `Localwire.UnityUIComponents.dll` over to your project's Assets folder 8 | * download repository, navigate to examples in **/examples/Localwire.UnityUIComponents.Examples/Assets/DLLs/** and copy over `Localwire.UnityUIComponents.dll` to your project's Assets folder 9 | 10 | ## Available components 11 | 12 | ### Autocomplete Textbox 13 | **[Documentation](https://github.com/m-wilczynski/UnityUIComponents/wiki/Autocomplete-Textbox) | [Live Preview](https://m-wilczynski.github.io/UnityUIComponents/examples/LivePreview/AutocompleteTextbox/)** 14 | 15 | 16 | Similiar to its web equivalents, **Autocomplete Textbox** listens to user input in `InputField` and after short delay (defined by user), queries provided source of `IAutocompleteSource` with input as criteria and prints results out to UI as `AutocompleteResultListElement`. 17 | Unlike most of built-in Unity3D components, selected item will not only be shown as string in `Text` component but also provided as actual, strongly-typed item of type `T` through `AutocompleteTextboxView.SelectedItem` property. 18 | 19 | 20 | **Example:** 21 | 22 | [![https://gyazo.com/66c4beeae56d77b9e0c4f658d8737167](https://i.gyazo.com/66c4beeae56d77b9e0c4f658d8737167.gif)](https://gyazo.com/66c4beeae56d77b9e0c4f658d8737167)
23 | -------------------------------------------------------------------------------- /docs/images/body-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-wilczynski/UnityUIComponents/11e63aac048d8f04fe76ffcd0a99aff9d2f2b4c4/docs/images/body-bg.jpg -------------------------------------------------------------------------------- /docs/images/download-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-wilczynski/UnityUIComponents/11e63aac048d8f04fe76ffcd0a99aff9d2f2b4c4/docs/images/download-button.png -------------------------------------------------------------------------------- /docs/images/github-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-wilczynski/UnityUIComponents/11e63aac048d8f04fe76ffcd0a99aff9d2f2b4c4/docs/images/github-button.png -------------------------------------------------------------------------------- /docs/images/header-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-wilczynski/UnityUIComponents/11e63aac048d8f04fe76ffcd0a99aff9d2f2b4c4/docs/images/header-bg.jpg -------------------------------------------------------------------------------- /docs/images/highlight-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-wilczynski/UnityUIComponents/11e63aac048d8f04fe76ffcd0a99aff9d2f2b4c4/docs/images/highlight-bg.jpg -------------------------------------------------------------------------------- /docs/images/sidebar-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-wilczynski/UnityUIComponents/11e63aac048d8f04fe76ffcd0a99aff9d2f2b4c4/docs/images/sidebar-bg.jpg -------------------------------------------------------------------------------- /docs/javascripts/main.js: -------------------------------------------------------------------------------- 1 | console.log('This would be the main JS file.'); 2 | -------------------------------------------------------------------------------- /docs/stylesheets/github-light.css: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2016 GitHub, Inc. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | .pl-c /* comment */ { 27 | color: #969896; 28 | } 29 | 30 | .pl-c1 /* constant, variable.other.constant, support, meta.property-name, support.constant, support.variable, meta.module-reference, markup.raw, meta.diff.header */, 31 | .pl-s .pl-v /* string variable */ { 32 | color: #0086b3; 33 | } 34 | 35 | .pl-e /* entity */, 36 | .pl-en /* entity.name */ { 37 | color: #795da3; 38 | } 39 | 40 | .pl-smi /* variable.parameter.function, storage.modifier.package, storage.modifier.import, storage.type.java, variable.other */, 41 | .pl-s .pl-s1 /* string source */ { 42 | color: #333; 43 | } 44 | 45 | .pl-ent /* entity.name.tag */ { 46 | color: #63a35c; 47 | } 48 | 49 | .pl-k /* keyword, storage, storage.type */ { 50 | color: #a71d5d; 51 | } 52 | 53 | .pl-s /* string */, 54 | .pl-pds /* punctuation.definition.string, string.regexp.character-class */, 55 | .pl-s .pl-pse .pl-s1 /* string punctuation.section.embedded source */, 56 | .pl-sr /* string.regexp */, 57 | .pl-sr .pl-cce /* string.regexp constant.character.escape */, 58 | .pl-sr .pl-sre /* string.regexp source.ruby.embedded */, 59 | .pl-sr .pl-sra /* string.regexp string.regexp.arbitrary-repitition */ { 60 | color: #183691; 61 | } 62 | 63 | .pl-v /* variable */ { 64 | color: #ed6a43; 65 | } 66 | 67 | .pl-id /* invalid.deprecated */ { 68 | color: #b52a1d; 69 | } 70 | 71 | .pl-ii /* invalid.illegal */ { 72 | color: #f8f8f8; 73 | background-color: #b52a1d; 74 | } 75 | 76 | .pl-sr .pl-cce /* string.regexp constant.character.escape */ { 77 | font-weight: bold; 78 | color: #63a35c; 79 | } 80 | 81 | .pl-ml /* markup.list */ { 82 | color: #693a17; 83 | } 84 | 85 | .pl-mh /* markup.heading */, 86 | .pl-mh .pl-en /* markup.heading entity.name */, 87 | .pl-ms /* meta.separator */ { 88 | font-weight: bold; 89 | color: #1d3e81; 90 | } 91 | 92 | .pl-mq /* markup.quote */ { 93 | color: #008080; 94 | } 95 | 96 | .pl-mi /* markup.italic */ { 97 | font-style: italic; 98 | color: #333; 99 | } 100 | 101 | .pl-mb /* markup.bold */ { 102 | font-weight: bold; 103 | color: #333; 104 | } 105 | 106 | .pl-md /* markup.deleted, meta.diff.header.from-file */ { 107 | color: #bd2c00; 108 | background-color: #ffecec; 109 | } 110 | 111 | .pl-mi1 /* markup.inserted, meta.diff.header.to-file */ { 112 | color: #55a532; 113 | background-color: #eaffea; 114 | } 115 | 116 | .pl-mdr /* meta.diff.range */ { 117 | font-weight: bold; 118 | color: #795da3; 119 | } 120 | 121 | .pl-mo /* meta.output */ { 122 | color: #1d3e81; 123 | } 124 | 125 | -------------------------------------------------------------------------------- /docs/stylesheets/print.css: -------------------------------------------------------------------------------- 1 | html, body, div, span, applet, object, iframe, 2 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 3 | a, abbr, acronym, address, big, cite, code, 4 | del, dfn, em, img, ins, kbd, q, s, samp, 5 | small, strike, strong, sub, sup, tt, var, 6 | b, u, i, center, 7 | dl, dt, dd, ol, ul, li, 8 | fieldset, form, label, legend, 9 | table, caption, tbody, tfoot, thead, tr, th, td, 10 | article, aside, canvas, details, embed, 11 | figure, figcaption, footer, header, hgroup, 12 | menu, nav, output, ruby, section, summary, 13 | time, mark, audio, video { 14 | padding: 0; 15 | margin: 0; 16 | font: inherit; 17 | font-size: 100%; 18 | vertical-align: baseline; 19 | border: 0; 20 | } 21 | /* HTML5 display-role reset for older browsers */ 22 | article, aside, details, figcaption, figure, 23 | footer, header, hgroup, menu, nav, section { 24 | display: block; 25 | } 26 | body { 27 | line-height: 1; 28 | } 29 | ol, ul { 30 | list-style: none; 31 | } 32 | blockquote, q { 33 | quotes: none; 34 | } 35 | blockquote:before, blockquote:after, 36 | q:before, q:after { 37 | content: ''; 38 | content: none; 39 | } 40 | table { 41 | border-spacing: 0; 42 | border-collapse: collapse; 43 | } 44 | body { 45 | font-family: 'Helvetica Neue', Helvetica, Arial, serif; 46 | font-size: 13px; 47 | line-height: 1.5; 48 | color: #000; 49 | } 50 | 51 | a { 52 | font-weight: bold; 53 | color: #d5000d; 54 | } 55 | 56 | header { 57 | padding-top: 35px; 58 | padding-bottom: 10px; 59 | } 60 | 61 | header h1 { 62 | font-size: 48px; 63 | font-weight: bold; 64 | line-height: 1.2; 65 | color: #303030; 66 | letter-spacing: -1px; 67 | } 68 | 69 | header h2 { 70 | font-size: 24px; 71 | font-weight: normal; 72 | line-height: 1.3; 73 | color: #aaa; 74 | letter-spacing: -1px; 75 | } 76 | #downloads { 77 | display: none; 78 | } 79 | #main_content { 80 | padding-top: 20px; 81 | } 82 | 83 | code, pre { 84 | margin-bottom: 30px; 85 | font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal; 86 | font-size: 12px; 87 | color: #222; 88 | } 89 | 90 | code { 91 | padding: 0 3px; 92 | } 93 | 94 | pre { 95 | padding: 20px; 96 | overflow: auto; 97 | border: solid 1px #ddd; 98 | } 99 | pre code { 100 | padding: 0; 101 | } 102 | 103 | ul, ol, dl { 104 | margin-bottom: 20px; 105 | } 106 | 107 | 108 | /* COMMON STYLES */ 109 | 110 | table { 111 | width: 100%; 112 | border: 1px solid #ebebeb; 113 | } 114 | 115 | th { 116 | font-weight: 500; 117 | } 118 | 119 | td { 120 | font-weight: 300; 121 | text-align: center; 122 | border: 1px solid #ebebeb; 123 | } 124 | 125 | form { 126 | padding: 20px; 127 | background: #f2f2f2; 128 | 129 | } 130 | 131 | 132 | /* GENERAL ELEMENT TYPE STYLES */ 133 | 134 | h1 { 135 | font-size: 2.8em; 136 | } 137 | 138 | h2 { 139 | margin-bottom: 8px; 140 | font-size: 22px; 141 | font-weight: bold; 142 | color: #303030; 143 | } 144 | 145 | h3 { 146 | margin-bottom: 8px; 147 | font-size: 18px; 148 | font-weight: bold; 149 | color: #d5000d; 150 | } 151 | 152 | h4 { 153 | font-size: 16px; 154 | font-weight: bold; 155 | color: #303030; 156 | } 157 | 158 | h5 { 159 | font-size: 1em; 160 | color: #303030; 161 | } 162 | 163 | h6 { 164 | font-size: .8em; 165 | color: #303030; 166 | } 167 | 168 | p { 169 | margin-bottom: 20px; 170 | font-weight: 300; 171 | } 172 | 173 | a { 174 | text-decoration: none; 175 | } 176 | 177 | p a { 178 | font-weight: 400; 179 | } 180 | 181 | blockquote { 182 | padding: 0 0 0 30px; 183 | margin-bottom: 20px; 184 | font-size: 1.6em; 185 | border-left: 10px solid #e9e9e9; 186 | } 187 | 188 | ul li { 189 | padding-left: 20px; 190 | list-style-position: inside; 191 | list-style: disc; 192 | } 193 | 194 | ol li { 195 | padding-left: 3px; 196 | list-style-position: inside; 197 | list-style: decimal; 198 | } 199 | 200 | dl dd { 201 | font-style: italic; 202 | font-weight: 100; 203 | } 204 | 205 | footer { 206 | padding-top: 20px; 207 | padding-bottom: 30px; 208 | margin-top: 40px; 209 | font-size: 13px; 210 | color: #aaa; 211 | } 212 | 213 | footer a { 214 | color: #666; 215 | } 216 | 217 | /* MISC */ 218 | .clearfix:after { 219 | display: block; 220 | height: 0; 221 | clear: both; 222 | visibility: hidden; 223 | content: '.'; 224 | } 225 | 226 | .clearfix {display: inline-block;} 227 | * html .clearfix {height: 1%;} 228 | .clearfix {display: block;} 229 | -------------------------------------------------------------------------------- /docs/stylesheets/stylesheet.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 | 3 | /** 4 | * 1. Set default font family to sans-serif. 5 | * 2. Prevent iOS text size adjust after orientation change, without disabling 6 | * user zoom. 7 | */ 8 | 9 | html { 10 | font-family: sans-serif; /* 1 */ 11 | -webkit-text-size-adjust: 100%; /* 2 */ 12 | -ms-text-size-adjust: 100%; /* 2 */ 13 | } 14 | 15 | /** 16 | * Remove default margin. 17 | */ 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | /* HTML5 display definitions 24 | ========================================================================== */ 25 | 26 | /** 27 | * Correct `block` display not defined for any HTML5 element in IE 8/9. 28 | * Correct `block` display not defined for `details` or `summary` in IE 10/11 29 | * and Firefox. 30 | * Correct `block` display not defined for `main` in IE 11. 31 | */ 32 | 33 | article, 34 | aside, 35 | details, 36 | figcaption, 37 | figure, 38 | footer, 39 | header, 40 | hgroup, 41 | main, 42 | menu, 43 | nav, 44 | section, 45 | summary { 46 | display: block; 47 | } 48 | 49 | /** 50 | * 1. Correct `inline-block` display not defined in IE 8/9. 51 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 52 | */ 53 | 54 | audio, 55 | canvas, 56 | progress, 57 | video { 58 | display: inline-block; /* 1 */ 59 | vertical-align: baseline; /* 2 */ 60 | } 61 | 62 | /** 63 | * Prevent modern browsers from displaying `audio` without controls. 64 | * Remove excess height in iOS 5 devices. 65 | */ 66 | 67 | audio:not([controls]) { 68 | display: none; 69 | height: 0; 70 | } 71 | 72 | /** 73 | * Address `[hidden]` styling not present in IE 8/9/10. 74 | * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. 75 | */ 76 | 77 | [hidden], 78 | template { 79 | display: none; 80 | } 81 | 82 | /* Links 83 | ========================================================================== */ 84 | 85 | /** 86 | * Remove the gray background color from active links in IE 10. 87 | */ 88 | 89 | a { 90 | background-color: transparent; 91 | } 92 | 93 | /** 94 | * Improve readability when focused and also mouse hovered in all browsers. 95 | */ 96 | 97 | a:active, 98 | a:hover { 99 | outline: 0; 100 | } 101 | 102 | /* Text-level semantics 103 | ========================================================================== */ 104 | 105 | /** 106 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome. 107 | */ 108 | 109 | abbr[title] { 110 | border-bottom: 1px dotted; 111 | } 112 | 113 | /** 114 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 115 | */ 116 | 117 | b, 118 | strong { 119 | font-weight: bold; 120 | } 121 | 122 | /** 123 | * Address styling not present in Safari and Chrome. 124 | */ 125 | 126 | dfn { 127 | font-style: italic; 128 | } 129 | 130 | /** 131 | * Address variable `h1` font-size and margin within `section` and `article` 132 | * contexts in Firefox 4+, Safari, and Chrome. 133 | */ 134 | 135 | h1 { 136 | margin: 0.67em 0; 137 | font-size: 2em; 138 | } 139 | 140 | /** 141 | * Address styling not present in IE 8/9. 142 | */ 143 | 144 | mark { 145 | color: #000; 146 | background: #ff0; 147 | } 148 | 149 | /** 150 | * Address inconsistent and variable font size in all browsers. 151 | */ 152 | 153 | small { 154 | font-size: 80%; 155 | } 156 | 157 | /** 158 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 159 | */ 160 | 161 | sub, 162 | sup { 163 | position: relative; 164 | font-size: 75%; 165 | line-height: 0; 166 | vertical-align: baseline; 167 | } 168 | 169 | sup { 170 | top: -0.5em; 171 | } 172 | 173 | sub { 174 | bottom: -0.25em; 175 | } 176 | 177 | /* Embedded content 178 | ========================================================================== */ 179 | 180 | /** 181 | * Remove border when inside `a` element in IE 8/9/10. 182 | */ 183 | 184 | img { 185 | border: 0; 186 | } 187 | 188 | /** 189 | * Correct overflow not hidden in IE 9/10/11. 190 | */ 191 | 192 | svg:not(:root) { 193 | overflow: hidden; 194 | } 195 | 196 | /* Grouping content 197 | ========================================================================== */ 198 | 199 | /** 200 | * Address margin not present in IE 8/9 and Safari. 201 | */ 202 | 203 | figure { 204 | margin: 1em 40px; 205 | } 206 | 207 | /** 208 | * Address differences between Firefox and other browsers. 209 | */ 210 | 211 | hr { 212 | height: 0; 213 | -moz-box-sizing: content-box; 214 | box-sizing: content-box; 215 | } 216 | 217 | /** 218 | * Contain overflow in all browsers. 219 | */ 220 | 221 | pre { 222 | overflow: auto; 223 | } 224 | 225 | /** 226 | * Address odd `em`-unit font size rendering in all browsers. 227 | */ 228 | 229 | code, 230 | kbd, 231 | pre, 232 | samp { 233 | font-family: monospace, monospace; 234 | font-size: 1em; 235 | } 236 | 237 | /* Forms 238 | ========================================================================== */ 239 | 240 | /** 241 | * Known limitation: by default, Chrome and Safari on OS X allow very limited 242 | * styling of `select`, unless a `border` property is set. 243 | */ 244 | 245 | /** 246 | * 1. Correct color not being inherited. 247 | * Known issue: affects color of disabled elements. 248 | * 2. Correct font properties not being inherited. 249 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 250 | */ 251 | 252 | button, 253 | input, 254 | optgroup, 255 | select, 256 | textarea { 257 | margin: 0; /* 3 */ 258 | font: inherit; /* 2 */ 259 | color: inherit; /* 1 */ 260 | } 261 | 262 | /** 263 | * Address `overflow` set to `hidden` in IE 8/9/10/11. 264 | */ 265 | 266 | button { 267 | overflow: visible; 268 | } 269 | 270 | /** 271 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 272 | * All other form control elements do not inherit `text-transform` values. 273 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 274 | * Correct `select` style inheritance in Firefox. 275 | */ 276 | 277 | button, 278 | select { 279 | text-transform: none; 280 | } 281 | 282 | /** 283 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 284 | * and `video` controls. 285 | * 2. Correct inability to style clickable `input` types in iOS. 286 | * 3. Improve usability and consistency of cursor style between image-type 287 | * `input` and others. 288 | */ 289 | 290 | button, 291 | html input[type="button"], /* 1 */ 292 | input[type="reset"], 293 | input[type="submit"] { 294 | -webkit-appearance: button; /* 2 */ 295 | cursor: pointer; /* 3 */ 296 | } 297 | 298 | /** 299 | * Re-set default cursor for disabled elements. 300 | */ 301 | 302 | button[disabled], 303 | html input[disabled] { 304 | cursor: default; 305 | } 306 | 307 | /** 308 | * Remove inner padding and border in Firefox 4+. 309 | */ 310 | 311 | button::-moz-focus-inner, 312 | input::-moz-focus-inner { 313 | padding: 0; 314 | border: 0; 315 | } 316 | 317 | /** 318 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 319 | * the UA stylesheet. 320 | */ 321 | 322 | input { 323 | line-height: normal; 324 | } 325 | 326 | /** 327 | * It's recommended that you don't attempt to style these elements. 328 | * Firefox's implementation doesn't respect box-sizing, padding, or width. 329 | * 330 | * 1. Address box sizing set to `content-box` in IE 8/9/10. 331 | * 2. Remove excess padding in IE 8/9/10. 332 | */ 333 | 334 | input[type="checkbox"], 335 | input[type="radio"] { 336 | box-sizing: border-box; /* 1 */ 337 | padding: 0; /* 2 */ 338 | } 339 | 340 | /** 341 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain 342 | * `font-size` values of the `input`, it causes the cursor style of the 343 | * decrement button to change from `default` to `text`. 344 | */ 345 | 346 | input[type="number"]::-webkit-inner-spin-button, 347 | input[type="number"]::-webkit-outer-spin-button { 348 | height: auto; 349 | } 350 | 351 | /** 352 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome. 353 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome 354 | * (include `-moz` to future-proof). 355 | */ 356 | 357 | input[type="search"] { 358 | -webkit-box-sizing: content-box; /* 2 */ 359 | -moz-box-sizing: content-box; 360 | box-sizing: content-box; 361 | -webkit-appearance: textfield; /* 1 */ 362 | } 363 | 364 | /** 365 | * Remove inner padding and search cancel button in Safari and Chrome on OS X. 366 | * Safari (but not Chrome) clips the cancel button when the search input has 367 | * padding (and `textfield` appearance). 368 | */ 369 | 370 | input[type="search"]::-webkit-search-cancel-button, 371 | input[type="search"]::-webkit-search-decoration { 372 | -webkit-appearance: none; 373 | } 374 | 375 | /** 376 | * Define consistent border, margin, and padding. 377 | */ 378 | 379 | fieldset { 380 | padding: 0.35em 0.625em 0.75em; 381 | margin: 0 2px; 382 | border: 1px solid #c0c0c0; 383 | } 384 | 385 | /** 386 | * 1. Correct `color` not being inherited in IE 8/9/10/11. 387 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 388 | */ 389 | 390 | legend { 391 | padding: 0; /* 2 */ 392 | border: 0; /* 1 */ 393 | } 394 | 395 | /** 396 | * Remove default vertical scrollbar in IE 8/9/10/11. 397 | */ 398 | 399 | textarea { 400 | overflow: auto; 401 | } 402 | 403 | /** 404 | * Don't inherit the `font-weight` (applied by a rule above). 405 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 406 | */ 407 | 408 | optgroup { 409 | font-weight: bold; 410 | } 411 | 412 | /* Tables 413 | ========================================================================== */ 414 | 415 | /** 416 | * Remove most spacing between table cells. 417 | */ 418 | 419 | table { 420 | border-spacing: 0; 421 | border-collapse: collapse; 422 | } 423 | 424 | td, 425 | th { 426 | padding: 0; 427 | } 428 | 429 | /* LAYOUT STYLES */ 430 | body { 431 | font-family: 'Helvetica Neue', Helvetica, Arial, serif; 432 | font-size: 15px; 433 | font-weight: 400; 434 | line-height: 1.5; 435 | color: #666; 436 | background: #fafafa url(../images/body-bg.jpg) 0 0 repeat; 437 | } 438 | 439 | p { 440 | margin-top: 0; 441 | } 442 | 443 | a { 444 | color: #2879d0; 445 | } 446 | a:hover { 447 | color: #2268b2; 448 | } 449 | 450 | header { 451 | padding-top: 40px; 452 | padding-bottom: 40px; 453 | font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; 454 | background: #2e7bcf url(../images/header-bg.jpg) 0 0 repeat-x; 455 | border-bottom: solid 1px #275da1; 456 | } 457 | 458 | header h1 { 459 | width: 540px; 460 | margin-top: 0; 461 | margin-bottom: 0.2em; 462 | font-size: 72px; 463 | font-weight: normal; 464 | line-height: 1; 465 | color: #fff; 466 | letter-spacing: -1px; 467 | } 468 | 469 | header h2 { 470 | width: 540px; 471 | margin-top: 0; 472 | margin-bottom: 0; 473 | font-size: 26px; 474 | font-weight: normal; 475 | line-height: 1.3; 476 | color: #9ddcff; 477 | letter-spacing: 0; 478 | } 479 | 480 | .inner { 481 | position: relative; 482 | width: 940px; 483 | margin: 0 auto; 484 | } 485 | 486 | #content-wrapper { 487 | padding-top: 30px; 488 | border-top: solid 1px #fff; 489 | } 490 | 491 | #main-content { 492 | float: left; 493 | width: 690px; 494 | } 495 | 496 | #main-content img { 497 | max-width: 100%; 498 | } 499 | 500 | aside#sidebar { 501 | float: right; 502 | width: 200px; 503 | min-height: 504px; 504 | padding-left: 20px; 505 | font-size: 12px; 506 | line-height: 1.3; 507 | background: transparent url(../images/sidebar-bg.jpg) 0 0 no-repeat; 508 | } 509 | 510 | aside#sidebar p.repo-owner, 511 | aside#sidebar p.repo-owner a { 512 | font-weight: bold; 513 | } 514 | 515 | #downloads { 516 | margin-bottom: 40px; 517 | } 518 | 519 | a.button { 520 | width: 134px; 521 | height: 58px; 522 | padding-top: 22px; 523 | padding-left: 68px; 524 | font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; 525 | font-size: 23px; 526 | line-height: 1.2; 527 | color: #fff; 528 | } 529 | a.button small { 530 | display: block; 531 | font-size: 11px; 532 | } 533 | header a.button { 534 | position: absolute; 535 | top: 0; 536 | right: 0; 537 | background: transparent url(../images/github-button.png) 0 0 no-repeat; 538 | } 539 | aside a.button { 540 | display: block; 541 | width: 138px; 542 | padding-left: 64px; 543 | margin-bottom: 20px; 544 | font-size: 21px; 545 | background: transparent url(../images/download-button.png) 0 0 no-repeat; 546 | } 547 | 548 | code, pre { 549 | margin-bottom: 30px; 550 | font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; 551 | font-size: 13px; 552 | color: #222; 553 | } 554 | 555 | code { 556 | padding: 0 3px; 557 | background-color: #f2f8fc; 558 | border: solid 1px #dbe7f3; 559 | } 560 | 561 | pre { 562 | padding: 20px; 563 | overflow: auto; 564 | text-shadow: none; 565 | background: #fff; 566 | border: solid 1px #f2f2f2; 567 | } 568 | pre code { 569 | padding: 0; 570 | color: #2879d0; 571 | background-color: #fff; 572 | border: none; 573 | } 574 | 575 | ul, ol, dl { 576 | margin-bottom: 20px; 577 | } 578 | 579 | 580 | /* COMMON STYLES */ 581 | 582 | hr { 583 | height: 0; 584 | margin-top: 1em; 585 | margin-bottom: 1em; 586 | border: 0; 587 | border-top: solid 1px #ddd; 588 | } 589 | 590 | table { 591 | width: 100%; 592 | border: 1px solid #ebebeb; 593 | } 594 | 595 | th { 596 | font-weight: 500; 597 | } 598 | 599 | td { 600 | font-weight: 300; 601 | text-align: center; 602 | border: 1px solid #ebebeb; 603 | } 604 | 605 | form { 606 | padding: 20px; 607 | background: #f2f2f2; 608 | 609 | } 610 | 611 | 612 | /* GENERAL ELEMENT TYPE STYLES */ 613 | 614 | #main-content h1 { 615 | margin-top: 0; 616 | margin-bottom: 0; 617 | font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; 618 | font-size: 2.8em; 619 | font-weight: normal; 620 | color: #474747; 621 | text-indent: 6px; 622 | letter-spacing: -1px; 623 | } 624 | 625 | #main-content h1:before { 626 | padding-right: 0.3em; 627 | margin-left: -0.9em; 628 | color: #9ddcff; 629 | content: "/"; 630 | } 631 | 632 | #main-content h2 { 633 | margin-bottom: 8px; 634 | font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; 635 | font-size: 22px; 636 | font-weight: bold; 637 | color: #474747; 638 | text-indent: 4px; 639 | } 640 | #main-content h2:before { 641 | padding-right: 0.3em; 642 | margin-left: -1.5em; 643 | content: "//"; 644 | color: #9ddcff; 645 | } 646 | 647 | #main-content h3 { 648 | margin-top: 24px; 649 | margin-bottom: 8px; 650 | font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; 651 | font-size: 18px; 652 | font-weight: bold; 653 | color: #474747; 654 | text-indent: 3px; 655 | } 656 | 657 | #main-content h3:before { 658 | padding-right: 0.3em; 659 | margin-left: -2em; 660 | content: "///"; 661 | color: #9ddcff; 662 | } 663 | 664 | #main-content h4 { 665 | margin-bottom: 8px; 666 | font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; 667 | font-size: 15px; 668 | font-weight: bold; 669 | color: #474747; 670 | text-indent: 3px; 671 | } 672 | 673 | h4:before { 674 | padding-right: 0.3em; 675 | margin-left: -2.8em; 676 | content: "////"; 677 | color: #9ddcff; 678 | } 679 | 680 | #main-content h5 { 681 | margin-bottom: 8px; 682 | font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; 683 | font-size: 14px; 684 | color: #474747; 685 | text-indent: 3px; 686 | } 687 | h5:before { 688 | padding-right: 0.3em; 689 | margin-left: -3.2em; 690 | content: "/////"; 691 | color: #9ddcff; 692 | } 693 | 694 | #main-content h6 { 695 | margin-bottom: 8px; 696 | font-family: 'Architects Daughter', 'Helvetica Neue', Helvetica, Arial, serif; 697 | font-size: .8em; 698 | color: #474747; 699 | text-indent: 3px; 700 | } 701 | h6:before { 702 | padding-right: 0.3em; 703 | margin-left: -3.7em; 704 | content: "//////"; 705 | color: #9ddcff; 706 | } 707 | 708 | p { 709 | margin-bottom: 20px; 710 | } 711 | 712 | a { 713 | text-decoration: none; 714 | } 715 | 716 | p a { 717 | font-weight: 400; 718 | } 719 | 720 | blockquote { 721 | padding: 0 0 0 30px; 722 | margin-bottom: 20px; 723 | font-size: 1.6em; 724 | border-left: 10px solid #e9e9e9; 725 | } 726 | 727 | ul { 728 | list-style-position: inside; 729 | list-style: disc; 730 | padding-left: 20px; 731 | } 732 | 733 | ol { 734 | list-style-position: inside; 735 | list-style: decimal; 736 | padding-left: 3px; 737 | } 738 | 739 | dl dd { 740 | font-style: italic; 741 | font-weight: 100; 742 | } 743 | 744 | footer { 745 | padding-top: 20px; 746 | padding-bottom: 30px; 747 | margin-top: 40px; 748 | font-size: 13px; 749 | color: #aaa; 750 | background: transparent url('../images/hr.png') 0 0 no-repeat; 751 | } 752 | 753 | footer a { 754 | color: #666; 755 | } 756 | footer a:hover { 757 | color: #444; 758 | } 759 | 760 | /* MISC */ 761 | .clearfix:after { 762 | display: block; 763 | height: 0; 764 | clear: both; 765 | visibility: hidden; 766 | content: '.'; 767 | } 768 | 769 | .clearfix {display: inline-block;} 770 | * html .clearfix {height: 1%;} 771 | .clearfix {display: block;} 772 | 773 | /* #Media Queries 774 | ================================================== */ 775 | 776 | /* Smaller than standard 960 (devices and browsers) */ 777 | @media only screen and (max-width: 959px) { } 778 | 779 | /* Tablet Portrait size to standard 960 (devices and browsers) */ 780 | @media only screen and (min-width: 768px) and (max-width: 959px) { 781 | .inner { 782 | width: 740px; 783 | } 784 | header h1, header h2 { 785 | width: 340px; 786 | } 787 | header h1 { 788 | font-size: 60px; 789 | } 790 | header h2 { 791 | font-size: 30px; 792 | } 793 | #main-content { 794 | width: 490px; 795 | } 796 | #main-content h1:before, 797 | #main-content h2:before, 798 | #main-content h3:before, 799 | #main-content h4:before, 800 | #main-content h5:before, 801 | #main-content h6:before { 802 | padding-right: 0; 803 | margin-left: 0; 804 | content: none; 805 | } 806 | } 807 | 808 | /* All Mobile Sizes (devices and browser) */ 809 | @media only screen and (max-width: 767px) { 810 | .inner { 811 | width: 93%; 812 | } 813 | header { 814 | padding: 20px 0; 815 | } 816 | header .inner { 817 | position: relative; 818 | } 819 | header h1, header h2 { 820 | width: 100%; 821 | } 822 | header h1 { 823 | font-size: 48px; 824 | } 825 | header h2 { 826 | font-size: 24px; 827 | } 828 | header a.button { 829 | position: relative; 830 | display: inline-block; 831 | width: auto; 832 | height: auto; 833 | padding: 5px 10px; 834 | margin-top: 15px; 835 | font-size: 13px; 836 | line-height: 1; 837 | color: #2879d0; 838 | text-align: center; 839 | background-color: #9ddcff; 840 | background-image: none; 841 | border-radius: 5px; 842 | -moz-border-radius: 5px; 843 | -webkit-border-radius: 5px; 844 | } 845 | header a.button small { 846 | display: inline; 847 | font-size: 13px; 848 | } 849 | #main-content, 850 | aside#sidebar { 851 | float: none; 852 | width: 100% ! important; 853 | } 854 | aside#sidebar { 855 | min-height: 0; 856 | padding: 20px 0; 857 | margin-top: 20px; 858 | background-image: none; 859 | border-top: solid 1px #ddd; 860 | } 861 | aside#sidebar a.button { 862 | display: none; 863 | } 864 | #main-content h1:before, 865 | #main-content h2:before, 866 | #main-content h3:before, 867 | #main-content h4:before, 868 | #main-content h5:before, 869 | #main-content h6:before { 870 | padding-right: 0; 871 | margin-left: 0; 872 | content: none; 873 | } 874 | } 875 | 876 | /* Mobile Landscape Size to Tablet Portrait (devices and browsers) */ 877 | @media only screen and (min-width: 480px) and (max-width: 767px) { } 878 | 879 | /* Mobile Portrait Size to Mobile Landscape Size (devices and browsers) */ 880 | @media only screen and (max-width: 479px) { } 881 | 882 | -------------------------------------------------------------------------------- /examples/LivePreview/AutocompleteTextbox/Autocomplete-Textbox.unity3d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-wilczynski/UnityUIComponents/11e63aac048d8f04fe76ffcd0a99aff9d2f2b4c4/examples/LivePreview/AutocompleteTextbox/Autocomplete-Textbox.unity3d -------------------------------------------------------------------------------- /examples/LivePreview/AutocompleteTextbox/UnityObject2.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileOverview 3 | * Defines UnityObject2 4 | */ 5 | 6 | 7 | //TODO: No need to polute the global space, just transfer this control to a 'static' variable insite unityObject! 8 | /** 9 | * @namespace 10 | */ 11 | //var unity = unity || {}; 12 | // We store all unityObject instances in a global scope, needed for IE firstFrameCallback and other internal tasks. 13 | //unity.instances = []; 14 | //unity.instanceNumber = 0; 15 | 16 | /** 17 | * Object expected by the Java Installer. We can move those to UnityObject2 if we update the java Installer. 18 | */ 19 | var unityObject = { 20 | /** 21 | * Callback used bt the Java installer to notify the Install Complete. 22 | * @private 23 | * @param {String} id 24 | * @param {bool} success 25 | * @param {String} errormessage 26 | */ 27 | javaInstallDone : function (id, success, errormessage) { 28 | 29 | var instanceId = parseInt(id.substring(id.lastIndexOf('_') + 1), 10); 30 | 31 | if (!isNaN(instanceId)) { 32 | 33 | // javaInstallDoneCallback must not be called directly because it deadlocks google chrome 34 | setTimeout(function () { 35 | 36 | UnityObject2.instances[instanceId].javaInstallDoneCallback(id, success, errormessage); 37 | }, 10); 38 | } 39 | } 40 | }; 41 | 42 | 43 | /** 44 | * @class 45 | * @constructor 46 | */ 47 | var UnityObject2 = function (config) { 48 | 49 | /** @private */ 50 | var logHistory = [], 51 | win = window, 52 | doc = document, 53 | nav = navigator, 54 | instanceNumber = null, 55 | //domLoaded = false, 56 | //domLoadEvents = [], 57 | embeddedObjects = [], //Could be removed? 58 | //listeners = [], 59 | //styleSheet = null, 60 | //styleSheetMedia = null, 61 | //autoHideShow = true, 62 | //fullSizeMissing = true, 63 | useSSL = (document.location.protocol == 'https:'), //This will turn off enableUnityAnalytics, since enableUnityAnalytics don't have a https version. 64 | baseDomain = useSSL ? "https://ssl-webplayer.unity3d.com/" : "http://webplayer.unity3d.com/", 65 | triedJavaCookie = "_unity_triedjava", 66 | triedJavaInstall = _getCookie(triedJavaCookie), 67 | triedClickOnceCookie = "_unity_triedclickonce", 68 | triedClickOnce = _getCookie(triedClickOnceCookie), 69 | progressCallback = false, 70 | applets = [], 71 | //addedClickOnce = false, 72 | googleAnalyticsLoaded = false, 73 | googleAnalyticsCallback = null, 74 | latestStatus = null, 75 | lastType = null, 76 | //beginCallback = [], 77 | //preCallback = [], 78 | imagesToWaitFor = [], 79 | //referrer = null, 80 | pluginStatus = null, 81 | pluginStatusHistory = [], 82 | installProcessStarted = false, //not used anymore? 83 | kInstalled = "installed", 84 | kMissing = "missing", 85 | kBroken = "broken", 86 | kUnsupported = "unsupported", 87 | kReady = "ready", //not used anymore? 88 | kStart = "start", 89 | kError = "error", 90 | kFirst = "first", 91 | //kStandard = "standard", 92 | kJava = "java", 93 | kClickOnce = "clickonce", //not used anymore? 94 | wasMissing = false, //identifies if this is a install attempt, or if the plugin was already installed 95 | unityObject = null, //The or for the webplayer. This can be used for webPlayer communication. 96 | //kApplet = "_applet", 97 | //kBanner = "_banner", 98 | 99 | cfg = { 100 | pluginName : "Unity Player", 101 | pluginMimeType : "application/vnd.unity", 102 | baseDownloadUrl : baseDomain + "download_webplayer-3.x/", 103 | fullInstall : false, 104 | autoInstall : false, 105 | enableJava : true, 106 | enableJVMPreloading : false, 107 | enableClickOnce : true, 108 | enableUnityAnalytics : false, 109 | enableGoogleAnalytics : true, 110 | enableBrowserDeprecatedWarning : true, 111 | params : {}, 112 | attributes : {}, 113 | referrer : null, 114 | debugLevel : 0, 115 | pluginVersionChecker : { 116 | container : jQuery("body")[0], 117 | hide : true, 118 | id : "version-checker" 119 | } 120 | }; 121 | 122 | // Merge in the given configuration and override defaults. 123 | cfg = jQuery.extend(true, cfg, config); 124 | 125 | if (cfg.referrer === "") { 126 | cfg.referrer = null; 127 | } 128 | //enableUnityAnalytics does not support SSL yet. 129 | if (useSSL) { 130 | cfg.enableUnityAnalytics = false; 131 | } 132 | 133 | /** 134 | * Get cookie value 135 | * @private 136 | * @param {String} name The param name 137 | * @return string or false if non-existing. 138 | */ 139 | function _getCookie(name) { 140 | 141 | var e = new RegExp(escape(name) + "=([^;]+)"); 142 | 143 | if (e.test(doc.cookie + ";")) { 144 | 145 | e.exec(doc.cookie + ";"); 146 | return RegExp.$1; 147 | } 148 | 149 | return false; 150 | } 151 | 152 | /** 153 | * Sets session cookie 154 | * @private 155 | */ 156 | function _setSessionCookie(name, value) { 157 | 158 | document.cookie = escape(name) + "=" + escape(value) + "; path=/"; 159 | } 160 | 161 | /** 162 | * Converts unity version to number (used for version comparison) 163 | * @private 164 | */ 165 | function _getNumericUnityVersion(version) { 166 | 167 | var result = 0, 168 | major, 169 | minor, 170 | fix, 171 | type, 172 | release; 173 | 174 | if (version) { 175 | 176 | var m = version.toLowerCase().match(/^(\d+)(?:\.(\d+)(?:\.(\d+)([dabfr])?(\d+)?)?)?$/); 177 | 178 | if (m && m[1]) { 179 | 180 | major = m[1]; 181 | minor = m[2] ? m[2] : 0; 182 | fix = m[3] ? m[3] : 0; 183 | type = m[4] ? m[4] : 'r'; 184 | release = m[5] ? m[5] : 0; 185 | result |= ((major / 10) % 10) << 28; 186 | result |= (major % 10) << 24; 187 | result |= (minor % 10) << 20; 188 | result |= (fix % 10) << 16; 189 | result |= {d: 2 << 12, a: 4 << 12, b: 6 << 12, f: 8 << 12, r: 8 << 12}[type]; 190 | result |= ((release / 100) % 10) << 8; 191 | result |= ((release / 10) % 10) << 4; 192 | result |= (release % 10); 193 | } 194 | } 195 | 196 | return result; 197 | } 198 | 199 | /** 200 | * Gets plugin and unity versions (non-ie) 201 | * @private 202 | */ 203 | function _getPluginVersion(callback, versions) { 204 | 205 | var b = cfg.pluginVersionChecker.container; 206 | var ue = doc.createElement("object"); 207 | var i = 0; 208 | 209 | if (b && ue) { 210 | ue.setAttribute("type", cfg.pluginMimeType); 211 | ue.setAttribute("id", cfg.pluginVersionChecker.id); 212 | if (cfg.pluginVersionChecker.hide) 213 | ue.style.visibility = "hidden"; 214 | b.appendChild(ue); 215 | 216 | (function () { 217 | if (typeof ue.GetPluginVersion === "undefined") { 218 | setTimeout(arguments.callee, 100); 219 | } else { 220 | 221 | var v = {}; 222 | 223 | if (versions) { 224 | 225 | for (i = 0; i < versions.length; ++i) { 226 | 227 | v[versions[i]] = ue.GetUnityVersion(versions[i]); 228 | } 229 | } 230 | 231 | v.plugin = ue.GetPluginVersion(); 232 | b.removeChild(ue); 233 | callback(v); 234 | } 235 | })(); 236 | 237 | } else { 238 | 239 | callback(null); 240 | } 241 | } 242 | 243 | /** 244 | * Retrieves windows installer name 245 | * @private 246 | */ 247 | function _getWinInstall() { 248 | var url = ""; 249 | 250 | if (ua.x64) { 251 | url = cfg.fullInstall ? "UnityWebPlayerFull64.exe" : "UnityWebPlayer64.exe"; 252 | } else { 253 | url = cfg.fullInstall ? "UnityWebPlayerFull.exe" : "UnityWebPlayer.exe"; 254 | } 255 | 256 | if (cfg.referrer !== null) { 257 | 258 | url += "?referrer=" + cfg.referrer; 259 | } 260 | return url; 261 | } 262 | 263 | /** 264 | * Retrieves mac plugin package name 265 | * @private 266 | */ 267 | function _getOSXInstall() { 268 | 269 | var url = "UnityPlayer.plugin.zip"; 270 | 271 | if (cfg.referrer != null) { 272 | 273 | url += "?referrer=" + cfg.referrer; 274 | } 275 | return url; 276 | } 277 | 278 | /** 279 | * retrieves installer name 280 | * @private 281 | */ 282 | function _getInstaller() { 283 | 284 | return cfg.baseDownloadUrl + (ua.win ? _getWinInstall() : _getOSXInstall() ); 285 | } 286 | 287 | /** 288 | * sets plugin status 289 | * @private 290 | */ 291 | function _setPluginStatus(status, type, data, url) { 292 | 293 | if (status === kMissing) { 294 | wasMissing = true; 295 | } 296 | 297 | // debug('setPluginStatus() status:', status, 'type:', type, 'data:', data, 'url:', url); 298 | 299 | // only report to analytics the first time a status occurs. 300 | if ( jQuery.inArray(status, pluginStatusHistory) === -1 ) { 301 | 302 | //Only send analytics for plugins installs. Do not send if plugin is already installed. 303 | if (wasMissing) { 304 | _an.send(status, type, data, url); 305 | } 306 | pluginStatusHistory.push(status); 307 | } 308 | 309 | pluginStatus = status; 310 | } 311 | 312 | 313 | /** 314 | * Contains browser and platform properties 315 | * @private 316 | */ 317 | var ua = function () { 318 | 319 | var a = nav.userAgent, p = nav.platform; 320 | var chrome = /chrome/i.test(a); 321 | 322 | //starting from IE 11, IE is using a different UserAgent. 323 | var ie = false; 324 | if (/msie/i.test(a)){ 325 | ie = parseFloat(a.replace(/^.*msie ([0-9]+(\.[0-9]+)?).*$/i, "$1")); 326 | } else if (/Trident/i.test(a)) { 327 | ie = parseFloat(a.replace(/^.*rv:([0-9]+(\.[0-9]+)?).*$/i, "$1")); 328 | } 329 | var ua = { 330 | w3 : typeof doc.getElementById != "undefined" && typeof doc.getElementsByTagName != "undefined" && typeof doc.createElement != "undefined", 331 | win : p ? /win/i.test(p) : /win/i.test(a), 332 | mac : p ? /mac/i.test(p) : /mac/i.test(a), 333 | ie : ie, 334 | ff : /firefox/i.test(a), 335 | op : /opera/i.test(a), 336 | ch : chrome, 337 | ch_v : /chrome/i.test(a) ? parseFloat(a.replace(/^.*chrome\/(\d+(\.\d+)?).*$/i, "$1")) : false, 338 | sf : /safari/i.test(a) && !chrome, 339 | wk : /webkit/i.test(a) ? parseFloat(a.replace(/^.*webkit\/(\d+(\.\d+)?).*$/i, "$1")) : false, 340 | x64 : /win64/i.test(a) && /x64/i.test(a), 341 | moz : /mozilla/i.test(a) ? parseFloat(a.replace(/^.*mozilla\/([0-9]+(\.[0-9]+)?).*$/i, "$1")) : 0, 342 | mobile: /ipad/i.test(p) || /iphone/i.test(p) || /ipod/i.test(p) || /android/i.test(a) || /windows phone/i.test(a), 343 | edge : /edge/i.test(a) ? parseFloat(a.replace(/^.*edge\/(\d+(\.\d+)?).*$/i, "$1")) : false 344 | }; 345 | 346 | ua.clientBrand = ua.edge ? 'edge' : ua.ch ? 'ch' : ua.ff ? 'ff' : ua.sf ? 'sf' : ua.ie ? 'ie' : ua.op ? 'op' : '??'; 347 | ua.clientPlatform = ua.win ? 'win' : ua.mac ? 'mac' : '???'; 348 | 349 | // get base url 350 | var s = doc.getElementsByTagName("script"); 351 | 352 | for (var i = 0; i < s.length; ++i) { 353 | 354 | var m = s[i].src.match(/^(.*)3\.0\/uo\/UnityObject2\.js$/i); 355 | 356 | if (m) { 357 | 358 | cfg.baseDownloadUrl = m[1]; 359 | break; 360 | } 361 | } 362 | 363 | /** 364 | * compares two versions 365 | * @private 366 | */ 367 | function _compareVersions(v1, v2) { 368 | 369 | for (var i = 0; i < Math.max(v1.length, v2.length); ++i) { 370 | 371 | var n1 = (i < v1.length) && v1[i] ? new Number(v1[i]) : 0; 372 | var n2 = (i < v2.length) && v2[i] ? new Number(v2[i]) : 0; 373 | if (n1 < n2) return -1; 374 | if (n1 > n2) return 1; 375 | } 376 | 377 | return 0; 378 | }; 379 | 380 | /** 381 | * detect java 382 | */ 383 | ua.java = function () { 384 | 385 | if (nav.javaEnabled()) { 386 | 387 | var wj = (ua.win && ua.ff); 388 | var mj = false;//(ua.mac && (ua.ff || ua.ch || ua.sf)); 389 | 390 | if (wj || mj) { 391 | 392 | if (typeof nav.mimeTypes != "undefined") { 393 | 394 | var rv = wj ? [1, 6, 0, 12] : [1, 4, 2, 0]; 395 | 396 | for (var i = 0; i < nav.mimeTypes.length; ++i) { 397 | 398 | if (nav.mimeTypes[i].enabledPlugin) { 399 | 400 | var m = nav.mimeTypes[i].type.match(/^application\/x-java-applet;(?:jpi-)?version=(\d+)(?:\.(\d+)(?:\.(\d+)(?:_(\d+))?)?)?$/); 401 | 402 | if (m != null) { 403 | 404 | if (_compareVersions(rv, m.slice(1)) <= 0) { 405 | 406 | return true; 407 | } 408 | } 409 | } 410 | } 411 | } 412 | } else if (ua.win && ua.ie) { 413 | 414 | if (typeof ActiveXObject != "undefined") { 415 | 416 | /** 417 | * ActiveX Test 418 | */ 419 | function _axTest(v) { 420 | 421 | try { 422 | 423 | return new ActiveXObject("JavaWebStart.isInstalled." + v + ".0") != null; 424 | } 425 | catch (ex) { 426 | 427 | return false; 428 | } 429 | } 430 | 431 | /** 432 | * ActiveX Test 2 433 | */ 434 | function _axTest2(v) { 435 | 436 | try { 437 | 438 | return new ActiveXObject("JavaPlugin.160_" + v) != null; 439 | } catch (ex) { 440 | 441 | return false; 442 | } 443 | } 444 | 445 | if (_axTest("1.7.0")) { 446 | 447 | return true; 448 | } 449 | 450 | if (ua.ie >= 8) { 451 | 452 | if (_axTest("1.6.0")) { 453 | 454 | // make sure it's 1.6.0.12 or newer. increment 50 to a larger value if 1.6.0.50 is released 455 | for (var i = 12; i <= 50; ++i) { 456 | 457 | if (_axTest2(i)) { 458 | 459 | if (ua.ie == 9 && ua.moz == 5 && i < 24) { 460 | // when IE9 is not in compatibility mode require at least 461 | // Java 1.6.0.24: http://support.microsoft.com/kb/2506617 462 | continue; 463 | } else { 464 | 465 | return true; 466 | } 467 | } 468 | } 469 | 470 | return false; 471 | } 472 | } else { 473 | 474 | return _axTest("1.6.0") || _axTest("1.5.0") || _axTest("1.4.2"); 475 | } 476 | } 477 | } 478 | } 479 | 480 | return false; 481 | }(); 482 | 483 | // detect clickonce 484 | ua.co = function () { 485 | 486 | if (ua.win && ua.ie) { 487 | var av = a.match(/(\.NET CLR [0-9.]+)|(\.NET[0-9.]+)/g); 488 | if (av != null) { 489 | var rv = [3, 5, 0]; 490 | for (var i = 0; i < av.length; ++i) { 491 | var versionNumbers = av[i].match(/[0-9.]{2,}/g)[0].split("."); 492 | if (_compareVersions(rv, versionNumbers) <= 0) { 493 | return true; 494 | } 495 | } 496 | } 497 | } 498 | return false; 499 | 500 | }(); 501 | 502 | return ua; 503 | }(); 504 | 505 | 506 | /** 507 | * analytics 508 | * @private 509 | */ 510 | var _an = function () { 511 | var uid = function () { 512 | 513 | var now = new Date(); 514 | var utc = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDay(), now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds(), now.getUTCMilliseconds()); 515 | return utc.toString(16) + _getRandomInt().toString(16); 516 | }(); 517 | var seq = 0; 518 | var _ugaq = window["_gaq"] = ( window["_gaq"] || [] ); 519 | 520 | _setUpAnalytics(); 521 | 522 | /** 523 | * generates random integer number 524 | * @private 525 | */ 526 | function _getRandomInt() { 527 | 528 | return Math.floor(Math.random() * 2147483647); 529 | } 530 | 531 | /** 532 | * Checks if there is a need to load analytics, by checking the existance of a _gaq object 533 | */ 534 | function _setUpAnalytics() { 535 | 536 | var gaUrl = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; 537 | var ss = doc.getElementsByTagName("script"); 538 | var googleAnalyticsLoaded = false; 539 | for (var i = 0; i < ss.length; ++i) { 540 | 541 | if (ss[i].src && ss[i].src.toLowerCase() == gaUrl.toLowerCase()) { 542 | 543 | googleAnalyticsLoaded = true; 544 | break; 545 | } 546 | } 547 | 548 | if (!googleAnalyticsLoaded) { 549 | var ga = doc.createElement("script"); 550 | ga.type = "text/javascript"; 551 | ga.async = true; 552 | ga.src = gaUrl; 553 | var s = document.getElementsByTagName("script")[0]; 554 | s.parentNode.insertBefore(ga, s); 555 | } 556 | 557 | var gaAccount = (cfg.debugLevel === 0) ? 'UA-16068464-16' : 'UA-16068464-17'; 558 | 559 | _ugaq.push(["unity._setDomainName", "none"]); 560 | _ugaq.push(["unity._setAllowLinker", true]); 561 | _ugaq.push(["unity._setReferrerOverride", ' '+this.location.toString()]); 562 | 563 | _ugaq.push(["unity._setAccount", gaAccount]); 564 | // $(GoogleRevisionPlaceholder) 565 | } 566 | 567 | /** 568 | * sends analytics data to unity 569 | * @private 570 | */ 571 | function _sendUnityAnalytics(event, type, data, callback) { 572 | 573 | if (!cfg.enableUnityAnalytics) { 574 | 575 | if (callback) { 576 | 577 | callback(); 578 | } 579 | 580 | return; 581 | } 582 | 583 | var url = "http://unityanalyticscapture.appspot.com/event?u=" + encodeURIComponent(uid) + "&s=" + encodeURIComponent(seq) + "&e=" + encodeURIComponent(event); 584 | // $(UnityRevisionPlaceholder) 585 | 586 | if (cfg.referrer !== null) { 587 | 588 | url += "?r=" + cfg.referrer; 589 | } 590 | 591 | if (type) { 592 | 593 | url += "&t=" + encodeURIComponent(type); 594 | } 595 | 596 | if (data) { 597 | 598 | url += "&d=" + encodeURIComponent(data); 599 | } 600 | 601 | var img = new Image(); 602 | 603 | if (callback) { 604 | 605 | img.onload = img.onerror = callback; 606 | } 607 | 608 | img.src = url; 609 | } 610 | 611 | /** 612 | * sends analytics data to google 613 | * @private 614 | */ 615 | function _sendGoogleAnalytics(event, type, data, callback) { 616 | 617 | if (!cfg.enableGoogleAnalytics) { 618 | 619 | if (callback) { 620 | 621 | callback(); 622 | } 623 | 624 | return; 625 | } 626 | 627 | var url = "/webplayer/install/" + event; 628 | var join = "?"; 629 | 630 | if (type) { 631 | 632 | url += join + "t=" + encodeURIComponent(type); 633 | join = "&"; 634 | } 635 | 636 | if (data) { 637 | 638 | url += join + "d=" + encodeURIComponent(data); 639 | join = "&"; 640 | } 641 | 642 | if (callback) { 643 | 644 | _ugaq.push(function () { 645 | setTimeout(callback,1000); 646 | //this.googleAnalyticsCallback = callback; 647 | }); 648 | } 649 | 650 | //try to shorten the URL to fit into customVariable 651 | //it will try to replace the early directories to .. 652 | var gameUrl = cfg.src; 653 | if (gameUrl.length > 40) { 654 | gameUrl = gameUrl.replace("http://",""); 655 | var paths = gameUrl.split("/"); 656 | 657 | var gameUrlFirst = paths.shift(); 658 | var gameUrlLast = paths.pop(); 659 | gameUrl = gameUrlFirst + "/../"+ gameUrlLast; 660 | 661 | while(gameUrl.length < 40 && paths.length > 0) { 662 | var nextpath = paths.pop(); 663 | if(gameUrl.length + nextpath.length + 5 < 40) { 664 | gameUrlLast = nextpath + "/" + gameUrlLast; 665 | } else { 666 | gameUrlLast = "../" + gameUrlLast; 667 | } 668 | gameUrl = gameUrlFirst + "/../"+ gameUrlLast; 669 | } 670 | } 671 | _ugaq.push(['unity._setCustomVar', 672 | 2, // This custom var is set to slot #1. Required parameter. 673 | 'GameURL', // The name acts as a kind of category for the user activity. Required parameter. 674 | gameUrl, // This value of the custom variable. Required parameter. 675 | 3 // Sets the scope to page-level. Optional parameter. 676 | ]); 677 | _ugaq.push(['unity._setCustomVar', 678 | 1, // This custom var is set to slot #1. Required parameter. 679 | 'UnityObjectVersion', // The name acts as a kind of category for the user activity. Required parameter. 680 | "2", // This value of the custom variable. Required parameter. 681 | 3 // Sets the scope to page-level. Optional parameter. 682 | ]); 683 | if (type) { 684 | _ugaq.push(['unity._setCustomVar', 685 | 3, // This custom var is set to slot #1. Required parameter. 686 | 'installMethod', // The name acts as a kind of category for the user activity. Required parameter. 687 | type, // This value of the custom variable. Required parameter. 688 | 3 // Sets the scope to page-level. Optional parameter. 689 | ]); 690 | } 691 | 692 | _ugaq.push(["unity._trackPageview", url]); 693 | } 694 | 695 | return { 696 | /** 697 | * sends analytics data. optionally opens url once data has been sent 698 | * @public 699 | */ 700 | send : function (event, type, data, url) { 701 | 702 | if (cfg.enableUnityAnalytics || cfg.enableGoogleAnalytics) { 703 | 704 | debug('Analytics SEND', event, type, data, url); 705 | } 706 | 707 | ++seq; 708 | var count = 2; 709 | 710 | var callback = function () { 711 | 712 | if (0 == --count) { 713 | 714 | googleAnalyticsCallback = null; 715 | window.location = url; 716 | } 717 | } 718 | 719 | if (data === null || data === undefined) { 720 | data = ""; 721 | } 722 | 723 | _sendUnityAnalytics(event, type, data, url ? callback : null); 724 | _sendGoogleAnalytics(event, type, data, url ? callback : null); 725 | } 726 | }; 727 | }(); 728 | 729 | 730 | 731 | 732 | 733 | /* Java Install - BEGIN */ 734 | 735 | /** 736 | * @private 737 | */ 738 | function _createObjectElement(attributes, params, elementToReplace) { 739 | 740 | var i, 741 | at, 742 | pt, 743 | ue, 744 | pe; 745 | 746 | if (ua.win && ua.ie) { 747 | 748 | at = ""; 749 | 750 | for (i in attributes) { 751 | 752 | at += ' ' + i + '="' + attributes[i] + '"'; 753 | } 754 | 755 | pt = ""; 756 | 757 | for (i in params) { 758 | 759 | pt += ''; 760 | } 761 | 762 | elementToReplace.outerHTML = '' + pt + ''; 763 | 764 | } else { 765 | 766 | ue = doc.createElement("object"); 767 | 768 | for (i in attributes) { 769 | 770 | ue.setAttribute(i, attributes[i]); 771 | } 772 | 773 | for (i in params) { 774 | 775 | pe = doc.createElement("param"); 776 | pe.name = i; 777 | pe.value = params[i]; 778 | ue.appendChild(pe); 779 | } 780 | 781 | elementToReplace.parentNode.replaceChild(ue, elementToReplace); 782 | } 783 | } 784 | 785 | /** 786 | * @private 787 | */ 788 | function _checkImage(img) { 789 | 790 | // img element not in the DOM yet 791 | if (typeof img == "undefined") { 792 | 793 | return false; 794 | } 795 | 796 | if (!img.complete) { 797 | 798 | return false; 799 | } 800 | 801 | // some browsers always return true in img.complete, for those 802 | // we can check naturalWidth 803 | if (typeof img.naturalWidth != "undefined" && img.naturalWidth == 0) { 804 | 805 | return false; 806 | } 807 | 808 | // no other way of checking, assuming it is ok 809 | return true; 810 | } 811 | 812 | /** 813 | * @private 814 | */ 815 | function _preloadJVMWhenReady(id) { 816 | 817 | var needToWait = false; 818 | 819 | for (var i = 0; i < imagesToWaitFor.length; i++) { 820 | if (!imagesToWaitFor[i]) { 821 | continue; 822 | } 823 | var img = doc.images[imagesToWaitFor[i]]; 824 | if (!_checkImage(img)) { 825 | needToWait = true; 826 | } 827 | else { 828 | imagesToWaitFor[i] = null; 829 | } 830 | } 831 | if (needToWait) { 832 | // check again in 100ms 833 | setTimeout(arguments.callee, 100); 834 | } 835 | else { 836 | // preload after a small delay, to make sure 837 | // the images have actually rendered 838 | setTimeout(function () { 839 | _preloadJVM(id); 840 | }, 100); 841 | } 842 | } 843 | 844 | 845 | /** 846 | * preloads the JVM and the Java Plug-in 847 | * @private 848 | */ 849 | function _preloadJVM(id) { 850 | 851 | var re = doc.getElementById(id); 852 | 853 | if (!re) { 854 | 855 | re = doc.createElement("div"); 856 | var lastBodyElem = doc.body.lastChild; 857 | doc.body.insertBefore(re, lastBodyElem.nextSibling); 858 | } 859 | 860 | var codebase = cfg.baseDownloadUrl + "3.0/jws/"; 861 | 862 | var a = { 863 | id : id, 864 | type : "application/x-java-applet", 865 | code : "JVMPreloader", 866 | width : 1, 867 | height : 1, 868 | name : "JVM Preloader" 869 | }; 870 | 871 | var p = { 872 | context : id, 873 | codebase : codebase, 874 | classloader_cache : false, 875 | scriptable : true, 876 | mayscript : true 877 | }; 878 | 879 | _createObjectElement(a, p, re); 880 | jQuery('#' + id).show(); 881 | //setVisibility(id, true); 882 | } 883 | 884 | /** 885 | * launches java installer 886 | * @private 887 | */ 888 | function _doJavaInstall(id) { 889 | 890 | triedJavaInstall = true; 891 | _setSessionCookie(triedJavaCookie, triedJavaInstall); 892 | var re = doc.getElementById(id); 893 | var appletID = id + "_applet_" + instanceNumber; 894 | 895 | applets[appletID] = { 896 | attributes : cfg.attributes, 897 | params : cfg.params, 898 | callback : cfg.callback, 899 | broken : cfg.broken 900 | }; 901 | 902 | var applet = applets[appletID]; 903 | 904 | var a = { 905 | id : appletID, 906 | type : "application/x-java-applet", 907 | archive : cfg.baseDownloadUrl + "3.0/jws/UnityWebPlayer.jar", 908 | code : "UnityWebPlayer", 909 | width : 1, 910 | height : 1, 911 | name : "Unity Web Player" 912 | }; 913 | 914 | if (ua.win && ua.ff) { 915 | 916 | a["style"] = "visibility: hidden;"; 917 | } 918 | 919 | var p = { 920 | context : appletID, 921 | jnlp_href : cfg.baseDownloadUrl + "3.0/jws/UnityWebPlayer.jnlp", 922 | classloader_cache : false, 923 | installer : _getInstaller(), 924 | image : baseDomain + "installation/unitylogo.png", 925 | centerimage : true, 926 | boxborder : false, 927 | scriptable : true, 928 | mayscript : true 929 | }; 930 | 931 | for (var i in applet.params) { 932 | 933 | if (i == "src") { 934 | 935 | continue; 936 | } 937 | 938 | if (applet.params[i] != Object.prototype[i]) { 939 | 940 | p[i] = applet.params[i]; 941 | 942 | if (i.toLowerCase() == "logoimage") { 943 | 944 | p["image"] = applet.params[i]; 945 | } 946 | else if (i.toLowerCase() == "backgroundcolor") { 947 | 948 | p["boxbgcolor"] = "#" + applet.params[i]; 949 | } 950 | else if (i.toLowerCase() == "bordercolor") { 951 | 952 | // there's no way to specify border color 953 | p["boxborder"] = true; 954 | } 955 | else if (i.toLowerCase() == "textcolor") { 956 | 957 | p["boxfgcolor"] = "#" + applet.params[i]; 958 | } 959 | } 960 | } 961 | 962 | // Create a dummy div element in the unityPlayer div 963 | // so that it can be replaced with the 1x1 px applet. 964 | // The applet will be resized when it has fully loaded, 965 | // see appletStarted(). 966 | var divToBeReplacedWithApplet = doc.createElement("div"); 967 | re.appendChild(divToBeReplacedWithApplet); 968 | _createObjectElement(a, p, divToBeReplacedWithApplet); 969 | jQuery('#' + id).show(); 970 | //setVisibility(appletID, true); 971 | } 972 | 973 | /** 974 | * @private 975 | */ 976 | function _jvmPreloaded(id) { 977 | 978 | // timeout prevents crash on ie 979 | setTimeout(function () { 980 | 981 | var re = doc.getElementById(id); 982 | 983 | if (re) { 984 | re.parentNode.removeChild(re); 985 | } 986 | }, 0); 987 | } 988 | 989 | /** 990 | * @private 991 | */ 992 | function _appletStarted(id) { 993 | // set the size of the applet to the one from cloned attributes 994 | var applet = applets[id], 995 | appletElement = doc.getElementById(id), 996 | childNode; 997 | 998 | // the applet might have already finished by now 999 | if (!appletElement) { 1000 | 1001 | return; 1002 | } 1003 | 1004 | appletElement.width = applet.attributes["width"] || 600; 1005 | appletElement.height = applet.attributes["height"] || 450; 1006 | 1007 | // remove all the siblings of the applet 1008 | var parentNode = appletElement.parentNode; 1009 | var childNodeList = parentNode.childNodes; 1010 | 1011 | for (var i = 0; i < childNodeList.length; i++) { 1012 | 1013 | childNode = childNodeList[i]; 1014 | // Compare the child node with our applet element only if 1015 | // it has the same type. Doing the comparison in other cases just 1016 | // jumps out of the loop. 1017 | if (childNode.nodeType == 1 && childNode != appletElement) { 1018 | 1019 | parentNode.removeChild(childNode); 1020 | } 1021 | } 1022 | } 1023 | 1024 | 1025 | // java installation callback 1026 | function _javaInstallDoneCallback(id, success, errormessage) { 1027 | 1028 | debug('_javaInstallDoneCallback', id, success, errormessage); 1029 | //console.log('javaInstallDoneCallback', id, success, errormessage); 1030 | 1031 | if (!success) { 1032 | 1033 | //var applet = applets[id]; 1034 | _setPluginStatus(kError, kJava, errormessage); 1035 | //createMissingUnity(id, applet.attributes, applet.params, applet.callback, applet.broken, kJava, errormessage); 1036 | } 1037 | } 1038 | 1039 | /* Java Install - END */ 1040 | 1041 | 1042 | /** 1043 | * @private 1044 | */ 1045 | function log() { 1046 | 1047 | logHistory.push(arguments); 1048 | 1049 | if ( cfg.debugLevel > 0 && window.console && window.console.log ) { 1050 | 1051 | console.log(Array.prototype.slice.call(arguments)); 1052 | //console.log.apply(console, Array.prototype.slice.call(arguments)); 1053 | } 1054 | } 1055 | 1056 | /** 1057 | * @private 1058 | */ 1059 | function debug() { 1060 | 1061 | logHistory.push(arguments); 1062 | 1063 | if ( cfg.debugLevel > 1 && window.console && window.console.log ) { 1064 | 1065 | console.log(Array.prototype.slice.call(arguments)); 1066 | //console.log.apply(console, Array.prototype.slice.call(arguments)); 1067 | } 1068 | } 1069 | 1070 | /** 1071 | * appends px to the value if it's a plain number 1072 | * @private 1073 | */ 1074 | function _appendPX(value) { 1075 | 1076 | if (/^[-+]?[0-9]+$/.test(value)) { 1077 | value += "px"; 1078 | } 1079 | return value; 1080 | } 1081 | 1082 | /** 1083 | * detects unity web player. 1084 | * @public 1085 | * callback - accepts two parameters. 1086 | * first one contains "installed", "missing", "broken" or "unsupported" value. 1087 | * second one returns requested unity versions. plugin version is included as well. 1088 | * versions - array of unity versions to detect. 1089 | */ 1090 | function _detectUnityInternal (callback, versions) { 1091 | 1092 | // console.debug('detectUnity this:', this); 1093 | var self = this; 1094 | 1095 | var status = kMissing; 1096 | var data; 1097 | nav.plugins.refresh(); 1098 | 1099 | if (ua.clientBrand === "??" || ua.clientPlatform === "???" || ua.mobile ) { 1100 | status = kUnsupported; 1101 | } else if (ua.op && ua.mac) { // Opera on MAC is unsupported 1102 | 1103 | status = kUnsupported; 1104 | data = "OPERA-MAC"; 1105 | } else if ( 1106 | typeof nav.plugins != "undefined" 1107 | && nav.plugins[cfg.pluginName] 1108 | && typeof nav.mimeTypes != "undefined" 1109 | && nav.mimeTypes[cfg.pluginMimeType] 1110 | && nav.mimeTypes[cfg.pluginMimeType].enabledPlugin 1111 | ) { 1112 | 1113 | status = kInstalled; 1114 | 1115 | // make sure web player is compatible with 64-bit safari 1116 | if (ua.sf && /Mac OS X 10_6/.test(nav.appVersion)) { 1117 | 1118 | _getPluginVersion(function (version) { 1119 | 1120 | if (!version || !version.plugin) { 1121 | 1122 | status = kBroken; 1123 | data = "OSX10.6-SFx64"; 1124 | } 1125 | 1126 | callback(status, lastType, data, version); 1127 | }, versions); 1128 | 1129 | return; 1130 | } else if (ua.mac && ua.ch) { // older versions have issues on chrome 1131 | 1132 | _getPluginVersion(function (version) { 1133 | 1134 | if (version && (_getNumericUnityVersion(version.plugin) <= _getNumericUnityVersion("2.6.1f3"))) { 1135 | status = kBroken; 1136 | data = "OSX-CH-U<=2.6.1f3"; 1137 | } 1138 | 1139 | callback(status, lastType, data, version); 1140 | }, versions); 1141 | 1142 | return; 1143 | } else if (versions) { 1144 | 1145 | _getPluginVersion(function (version) { 1146 | callback(status, lastType, data, version); 1147 | }, versions); 1148 | return; 1149 | } 1150 | } else if (ua.ie) { 1151 | var activeXSupported = false; 1152 | try { 1153 | if (ActiveXObject.prototype != null) { 1154 | activeXSupported = true; 1155 | } 1156 | } catch(e) {} 1157 | 1158 | if (!activeXSupported) { 1159 | status = kUnsupported; 1160 | data = "ActiveXFailed"; 1161 | } else { 1162 | status = kMissing; 1163 | try { 1164 | var uo = new ActiveXObject("UnityWebPlayer.UnityWebPlayer.1"); 1165 | var pv = uo.GetPluginVersion(); 1166 | 1167 | if (versions) { 1168 | var v = {}; 1169 | for (var i = 0; i < versions.length; ++i) { 1170 | v[versions[i]] = uo.GetUnityVersion(versions[i]); 1171 | } 1172 | v.plugin = pv; 1173 | } 1174 | 1175 | status = kInstalled; 1176 | // 2.5.0 auto update has issues on vista and later 1177 | if (pv == "2.5.0f5") { 1178 | var m = /Windows NT \d+\.\d+/.exec(nav.userAgent); 1179 | if (m && m.length > 0) { 1180 | var wv = parseFloat(m[0].split(' ')[2]); 1181 | if (wv >= 6) { 1182 | status = kBroken; 1183 | data = "WIN-U2.5.0f5"; 1184 | } 1185 | } 1186 | } 1187 | } catch(e) {} 1188 | } 1189 | } 1190 | callback(status, lastType, data, v); 1191 | } 1192 | 1193 | /** 1194 | * Detects unity web player. But doesn't modify the current UnityObject instance, and doesn't send analytics. 1195 | * @public 1196 | * callback - accepts two parameters. 1197 | * first one contains "installed", "missing", "broken" or "unsupported" value. 1198 | * second one returns requested unity versions. plugin version is included as well. 1199 | * versions - array of unity versions to detect. 1200 | */ 1201 | function _detectUnityNoAnalytics (callback, versions) { 1202 | _detectUnityInternal(function(status, lastType, data, v){ 1203 | callback(status, v); 1204 | }, versions); 1205 | } 1206 | 1207 | /** 1208 | * Detects unity web player. Also modify the current UnityObject instance, and sends analytics. 1209 | * @public 1210 | * callback - accepts two parameters. 1211 | * first one contains "installed", "missing", "broken" or "unsupported" value. 1212 | * second one returns requested unity versions. plugin version is included as well. 1213 | * versions - array of unity versions to detect. 1214 | */ 1215 | function _detectUnityWithAnalytics (callback, versions) { 1216 | _detectUnityInternal(function(status, lastType, data, v){ 1217 | _setPluginStatus(status, lastType, data); 1218 | callback(status, v); 1219 | }, versions); 1220 | } 1221 | 1222 | 1223 | var publicAPI = /** @lends UnityObject2.prototype */ { 1224 | 1225 | /** 1226 | * Get Debug Level (0=Disabled) 1227 | * @public 1228 | * @return {Number} Debug Level 1229 | */ 1230 | getLogHistory: function () { 1231 | 1232 | return logHistory; // JSON.stringify() 1233 | }, 1234 | 1235 | 1236 | /** 1237 | * Get configuration object 1238 | * @public 1239 | * @return {Object} cfg 1240 | */ 1241 | getConfig: function () { 1242 | 1243 | return cfg; // JSON.stringify() 1244 | }, 1245 | 1246 | 1247 | /** 1248 | * @public 1249 | * @return {Object} detailed info about OS and Browser. 1250 | */ 1251 | getPlatformInfo: function () { 1252 | 1253 | return ua; 1254 | }, 1255 | 1256 | 1257 | /** 1258 | * Initialize plugin config and proceed with attempting to start the webplayer. 1259 | * @public 1260 | */ 1261 | initPlugin: function (targetEl, src) { 1262 | 1263 | cfg.targetEl = targetEl; 1264 | cfg.src = src; 1265 | 1266 | debug('ua:', ua); 1267 | //console.debug('initPlugin this:', this); 1268 | //_detectUnityWithAnalytics(this.handlePluginStatus); 1269 | var self = this; 1270 | _detectUnityWithAnalytics(function(status, v){ 1271 | self.handlePluginStatus(status, v); 1272 | }); 1273 | }, 1274 | 1275 | 1276 | /** 1277 | * detects unity web player. 1278 | * @public 1279 | * callback - accepts two parameters. 1280 | * first one contains "installed", "missing", "broken" or "unsupported" value. 1281 | * second one returns requested unity versions. plugin version is included as well. 1282 | * versions - optional array of unity versions to detect. 1283 | */ 1284 | detectUnity: function (callback, versions) { 1285 | var self = this; 1286 | _detectUnityNoAnalytics(function(status, v){ 1287 | callback.call(self, status, v); 1288 | }, versions); 1289 | }, 1290 | 1291 | 1292 | 1293 | /** 1294 | * @public 1295 | * @return {Object} with info about Unity WebPlayer plugin status (not installed, loading, running etc..) 1296 | */ 1297 | handlePluginStatus: function (status, versions) { 1298 | 1299 | // Store targetEl in the closure, to be able to get it back if setTimeout calls again. 1300 | var targetEl = cfg.targetEl; 1301 | 1302 | var $targetEl = jQuery(targetEl); 1303 | 1304 | switch(status) { 1305 | 1306 | case kInstalled: 1307 | 1308 | // @todo add support for alternate custom handlers. 1309 | this.notifyProgress($targetEl); 1310 | this.embedPlugin($targetEl, cfg.callback); 1311 | break; 1312 | 1313 | case kMissing: 1314 | 1315 | this.notifyProgress($targetEl); 1316 | //this.installPlugin($targetEl); 1317 | 1318 | var self = this; 1319 | var delayTime = (cfg.debugLevel === 0) ? 1000 : 8000; 1320 | 1321 | // Do a delay and re-check for plugin 1322 | setTimeout(function () { 1323 | 1324 | cfg.targetEl = targetEl; 1325 | self.detectUnity(self.handlePluginStatus); 1326 | }, delayTime); 1327 | 1328 | break; 1329 | 1330 | case kBroken: 1331 | // Browser needs to restart after install 1332 | this.notifyProgress($targetEl); 1333 | break; 1334 | 1335 | case kUnsupported: 1336 | 1337 | this.notifyProgress($targetEl); 1338 | break; 1339 | } 1340 | 1341 | }, 1342 | 1343 | /** 1344 | * @public 1345 | * @return {Object} with detailed plugin info, version number and other info that can be retrieved from the plugin. 1346 | */ 1347 | /*getPluginInfo: function () { 1348 | 1349 | },*/ 1350 | 1351 | /** 1352 | * @public 1353 | */ 1354 | getPluginURL: function () { 1355 | 1356 | var url = "http://unity3d.com/webplayer/"; 1357 | 1358 | if (ua.win) { 1359 | 1360 | url = cfg.baseDownloadUrl + _getWinInstall(); 1361 | 1362 | } else if (nav.platform == "MacIntel") { 1363 | 1364 | url = cfg.baseDownloadUrl + (cfg.fullInstall ? "webplayer-i386.dmg" : "webplayer-mini.dmg"); 1365 | 1366 | if (cfg.referrer !== null) { 1367 | 1368 | url += "?referrer=" + cfg.referrer; 1369 | } 1370 | 1371 | } else if (nav.platform == "MacPPC") { 1372 | 1373 | url = cfg.baseDownloadUrl + (cfg.fullInstall ? "webplayer-ppc.dmg" : "webplayer-mini.dmg"); 1374 | 1375 | if (cfg.referrer !== null) { 1376 | 1377 | url += "?referrer=" + cfg.referrer; 1378 | } 1379 | } 1380 | 1381 | return url; 1382 | }, 1383 | 1384 | /** 1385 | * @public 1386 | */ 1387 | getClickOnceURL: function () { 1388 | 1389 | return cfg.baseDownloadUrl + "3.0/co/UnityWebPlayer.application?installer=" + encodeURIComponent(cfg.baseDownloadUrl + _getWinInstall()); 1390 | }, 1391 | 1392 | /** 1393 | * Embed the plugin into the DOM. 1394 | * @public 1395 | */ 1396 | embedPlugin: function (targetEl, callback) { 1397 | 1398 | targetEl = jQuery(targetEl).empty(); 1399 | 1400 | var src = cfg.src; //targetEl.data('src'), 1401 | var width = cfg.width || "100%"; //TODO: extract those hardcoded values 1402 | var height = cfg.height || "100%"; 1403 | var self = this; 1404 | 1405 | if (ua.win && ua.ie) { 1406 | // ie, dom and object element do not mix & match 1407 | 1408 | var at = ""; 1409 | 1410 | for (var i in cfg.attributes) { 1411 | if (cfg.attributes[i] != Object.prototype[i]) { 1412 | if (i.toLowerCase() == "styleclass") { 1413 | at += ' class="' + cfg.attributes[i] + '"'; 1414 | } 1415 | else if (i.toLowerCase() != "classid") { 1416 | at += ' ' + i + '="' + cfg.attributes[i] + '"'; 1417 | } 1418 | } 1419 | } 1420 | 1421 | var pt = ""; 1422 | 1423 | // we manually add SRC here, because its now defined on the target element. 1424 | pt += ''; 1425 | pt += ''; 1426 | 1427 | for (var i in cfg.params) { 1428 | 1429 | if (cfg.params[i] != Object.prototype[i]) { 1430 | 1431 | if (i.toLowerCase() != "classid") { 1432 | 1433 | pt += ''; 1434 | } 1435 | } 1436 | } 1437 | 1438 | //var tmpHtml = '
' + pt + '
'; 1439 | var tmpHtml = '' + pt + ''; 1440 | var $object = jQuery(tmpHtml); 1441 | targetEl.append( $object ); 1442 | embeddedObjects.push( targetEl.attr('id') ); 1443 | unityObject = $object[0]; 1444 | 1445 | } else { 1446 | 1447 | // Create and append embed element into DOM. 1448 | var $embed = jQuery('') 1449 | .attr({ 1450 | src: src, 1451 | type: cfg.pluginMimeType, 1452 | width: width, 1453 | height: height, 1454 | firstFrameCallback: 'UnityObject2.instances[' + instanceNumber + '].firstFrameCallback();' 1455 | }) 1456 | .attr(cfg.attributes) 1457 | .attr(cfg.params) 1458 | .css({ 1459 | display: 'block', 1460 | width: _appendPX(width), 1461 | height: _appendPX(height) 1462 | }) 1463 | .appendTo( targetEl ); 1464 | unityObject = $embed[0]; 1465 | } 1466 | 1467 | //Auto focus the new object/embed, so players dont have to click it before using it. 1468 | //setTimeout is here to workaround a chrome bug. 1469 | //we should not invoke focus on safari on mac. it causes some Input bugs. 1470 | if (!ua.sf || !ua.mac) { 1471 | setTimeout(function() { 1472 | unityObject.focus(); 1473 | }, 100); 1474 | } 1475 | 1476 | if (callback) { 1477 | 1478 | callback(); 1479 | } 1480 | }, 1481 | 1482 | /** 1483 | * Determine which installation method to use on the current platform, and return an array with their identifiers (i.e. 'ClickOnceIE', 'JavaInstall', 'Manual') 1484 | * Take into account which previous methods might have been attempted (and failed) and skip to next best method. 1485 | * @public 1486 | * @return {String} 1487 | */ 1488 | getBestInstallMethod: function () { 1489 | 1490 | // Always fall back to good old manual (download) install. 1491 | var method = 'Manual'; 1492 | 1493 | //We only have manual install for 64bit plugin so far. 1494 | if (ua.x64) 1495 | return method; 1496 | 1497 | // Is Java available and not yet attempted? 1498 | if (cfg.enableJava && ua.java && triedJavaInstall === false) { 1499 | 1500 | method = 'JavaInstall'; 1501 | } 1502 | // Is ClickOnce available and not yet attempted? 1503 | else if (cfg.enableClickOnce && ua.co && triedClickOnce === false) { 1504 | 1505 | method = 'ClickOnceIE'; 1506 | } 1507 | 1508 | return method; 1509 | }, 1510 | 1511 | /** 1512 | * Tries to install the plugin using the specified method. 1513 | * If no method is passed, it will try to use this.getBestInstallMethod() 1514 | * @public 1515 | * @param {String} method The desired install method 1516 | */ 1517 | installPlugin: function(method) { 1518 | if (method == null || method == undefined) { 1519 | method = this.getBestInstallMethod(); 1520 | } 1521 | 1522 | var urlToOpen = null; 1523 | switch(method) { 1524 | 1525 | case "JavaInstall": 1526 | this.doJavaInstall(cfg.targetEl.id); 1527 | break; 1528 | case "ClickOnceIE": 1529 | triedClickOnce = true; 1530 | _setSessionCookie(triedClickOnceCookie, triedClickOnce); 1531 | var $iframe = jQuery("