diff --git a/.gitignore b/.gitignore index 56a409a7..5e5788ee 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,516 @@ -# Created by .ignore support plugin (hsz.mobi) -web-widget/node_modules \ No newline at end of file + +# Created by https://www.toptal.com/developers/gitignore/api/node,jetbrains+all,visualstudiocode,react,reactnative +# Edit at https://www.toptal.com/developers/gitignore?templates=node,jetbrains+all,visualstudiocode,react,reactnative + +### JetBrains+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# 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 + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### JetBrains+all Patch ### +# Ignores the whole .idea folder and all .iml files +# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 + +.idea/ + +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 + +*.iml +modules.xml +.idea/misc.xml +*.ipr + +# Sonarlint plugin +.idea/sonarlint + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test +.env.production + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +### Node Patch ### +# Serverless Webpack directories +.webpack/ + +# Optional stylelint cache +.stylelintcache + +# SvelteKit build / generate output +.svelte-kit + +### react ### +.DS_* +**/*.backup.* +**/*.back.* + +node_modules + +*.sublime* + +psd +thumb +sketch + +### ReactNative ### +# React Native Stack Base + +.expo +__generated__ + +### ReactNative.Android Stack ### +# Built application files +*.apk +*.aar +*.ap_ +*.aab + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +# Uncomment the following line in case you need and you don't have the release build type files in your app +# release/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# IntelliJ +.idea/workspace.xml +.idea/tasks.xml +.idea/gradle.xml +.idea/assetWizardSettings.xml +.idea/dictionaries +.idea/libraries +.idea/jarRepositories.xml +# Android Studio 3 in .gitignore file. +.idea/caches +.idea/modules.xml +# Comment next line if keeping position of elements in Navigation Editor is relevant for you +.idea/navEditor.xml + +# Keystore files +# Uncomment the following lines if you do not want to check your keystore files in. +#*.jks +#*.keystore + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild +.cxx/ + +# Google Services (e.g. APIs or Firebase) +# google-services.json + +# Freeline +freeline.py +freeline/ +freeline_project_description.json + +# fastlane +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output +fastlane/readme.md + +# Version control +vcs.xml + +# lint +lint/intermediates/ +lint/generated/ +lint/outputs/ +lint/tmp/ +# lint/reports/ + +# Android Profiling +*.hprof + +### ReactNative.Buck Stack ### +buck-out/ +.buckconfig.local +.buckd/ +.buckversion +.fakebuckversion + +### ReactNative.Gradle Stack ### +.gradle + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Cache of project +.gradletasknamecache + +# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 +# gradle/wrapper/gradle-wrapper.properties + +### ReactNative.Linux Stack ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### ReactNative.Node Stack ### +# Logs + +# Diagnostic reports (https://nodejs.org/api/report.html) + +# Runtime data + +# Directory for instrumented libs generated by jscoverage/JSCover + +# Coverage directory used by tools like istanbul + +# nyc test coverage + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +# Bower dependency directory (https://bower.io/) + +# node-waf configuration + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +# Dependency directories + +# Snowpack dependency directory (https://snowpack.dev/) + +# TypeScript cache + +# Optional npm cache directory + +# Optional eslint cache + +# Microbundle cache + +# Optional REPL history + +# Output of 'npm pack' + +# Yarn Integrity file + +# dotenv environment variables file + +# parcel-bundler cache (https://parceljs.org/) + +# Next.js build output + +# Nuxt.js build / generate output + +# Gatsby files +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output + +# Serverless directories + +# FuseBox cache + +# DynamoDB Local files + +# TernJS port file + +# Stores VSCode versions used for testing VSCode extensions + +# yarn v2 + +### ReactNative.Xcode Stack ### +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 + +## Gcc Patch +/*.gcno + +### ReactNative.macOS Stack ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# Support for Project snippet scope +!.vscode/*.code-snippets + +# End of https://www.toptal.com/developers/gitignore/api/node,jetbrains+all,visualstudiocode,react,reactnative + + +package-lock.json +yarn.lock diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 00000000..a8363dda --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Sendbird + +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/README.md b/README.md index 51a9ec6d..623dc870 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,75 @@ -# SendBird JavaScript Sample +# Sendbird JavaScript SDK v3 samples +![Platform](https://img.shields.io/badge/platform-JAVASCRIPT-orange.svg) +![Languages](https://img.shields.io/badge/language-JAVASCRIPT-orange.svg) +[![npm](https://img.shields.io/npm/v/sendbird.svg?style=popout&colorB=red)](https://www.npmjs.com/package/sendbird) -The samples in this repository are fully functional messaging applications built using the [SendBird](https://sendbird.com) JS SDK. - 1. **Web widget sample:** Facebook-chat-like chat widget to regular websites. - 1. **React Native sample:** Mobile chat sample for iOS and Android. - 1. **Web sample:** Slack-like full screen chat sample for desktop browsers. +## Deprecation Note (v3) +:warning: Please note that Sendbird’s SDK v3 will be deprecated by **July 2023**. You may still use the older SDKs at your choice, but no new updates or bug fixes will be made to SDK v3. +**We recommend clients to plan their migration to SDK v4 as early as possible as there are breaking changes.** We also provide prioritized support for migration and any issues related to v4. SDK v4 provides far richer and robust features in Websocket, Local caching, Polls, Scheduled Messages, Pinned Message, and many more. So try it out now! ([Chat SDK v4 react samples](https://github.com/sendbird/sendbird-chat-sample-react/)) -## Table of Contents +
- 1. [Installing the SendBird JS SDK](#installing-the-sendbird-js-sdk) - 1. [Previous versions](#previous-versions) - 1. [Contributing](#contributing) - -## Installing the SendBird JS SDK - -Using [Bower](http://bower.io): +## 🔒 Security tip +When a new Sendbird application is created in the dashboard the default security settings are set permissive to simplify running samples and implementing your first code. - bower install sendbird +Before launching make sure to review the security tab under ⚙️ Settings -> Security, and set Access token permission to Read Only or Disabled so that unauthenticated users can not login as someone else. And review the Access Control lists. Most apps will want to disable "Allow retrieving user list" as that could expose usage numbers and other information. +## Introduction -Using [npm](https://www.npmjs.com/package/sendbird): +This repository contains samples for how to use Sendbird to add chat using Javascript, React and React Native. You can find more information in the [Javascript SDK documentation](https://sendbird.com/docs/chat/v3/javascript/getting-started/about-chat-sdk) and [React Quickstart Documentation](https://sendbird.com/docs/uikit/v1/react/quickstart/send-first-message) - npm install sendbird +![UIKit](asset/uikit.png) -> We now support both React Native and NodeJS. +### React +Sendbird UIKit for React is a set of prebuilt UI components that allows you to easily craft an in-app chat with all the essential messaging features. Our development kit includes light and dark themes, text fonts, colors and more. All the included components can be styled and customized to create an unique experience that fits your app. +- [**Basic React App**](https://github.com/sendbird/SendBird-JavaScript/tree/master/react/react-app-simple) is a quickest way to get started using UIKit -### Manual download - -Or, you can manually download the JS SDK files [here](https://github.com/smilefam/SendBird-SDK-JavaScript). +- [**Composed React App**](https://github.com/sendbird/SendBird-JavaScript/tree/master/react/react-app-custom) demonstrates how to use the various smart components. +- [**Custom React App**](https://github.com/sendbird/SendBird-JavaScript/tree/master/react/react-app-custom) shows how to customize the **Message**, **ChannelPreview**, and **UserList** UI elements. -## Previous versions -To view the version 2 sample, checkout the `v2` branch instead of `master.` +### React Native +The Sendbird React Native framework allows you to simplify development for iOS and Android apps, and reuse the same code on both web and mobile apps. +- [**React native Redux**](https://github.com/sendbird/SendBird-JavaScript/tree/master/react-native/react-native-redux) shows how to use Sendbird with React Native on iOS and Android. -## Contributing +- [**React native Redux Syncmanager**](https://github.com/sendbird/SendBird-JavaScript/tree/master/react-native/react-native-redux-syncmanager) Expands on the above sample and implements the [Sendbird SyncManager](https://github.com/sendbird/sendbird-syncmanager-javascript) -The SendBird JavaScript samples are fully open-source. All contributions and suggestions are welcome! +- [**React Native Hooks**](https://github.com/sendbird/SendBird-JavaScript/tree/master/react-native/react-native-hook) Implements Sendbird on iOS and Android using the hooks pattern. + + +### JavaScript + +- [**JavaScript chat sample**](https://github.com/sendbird/SendBird-JavaScript/tree/master/javascript/javascript-basic) is a Slack-like full screen chat sample for desktop browsers using both Group channels and open channels. + +- [**JavaScript widget sample**](https://github.com/sendbird/SendBird-JavaScript/tree/master/javascript/javascript-widget) is a Facebook-chat-like chat widget for websites. + +- [**JavaScript live chat sample**](https://github.com/sendbird/SendBird-JavaScript/tree/master/javascript/javascript-live-chat) is a Twitch-chat-like experience. + +- [**JavaScript chat sample with SyncManager**](https://github.com/sendbird/sendbird-javascript-samples/tree/master/javascript/javascript-basic-syncmanager) is a web chat sample integrated with [Sendbird SyncManager document](https://sendbird.com/docs/syncmanager/v1/javascript/getting-started/about-syncmanager), adds local caching to the core chat features. For faster data loading and caching, the sample synchronizes with the Sendbird server and saves a list of group channels and the messages within the local cache into your client app. + +## Installation + +To use the Sendbird Chat SDK directly you can install it through npm or yarn with + +```bash +npm install --save sendbird +``` +or + +```bash +yarn install --save sendbird +``` + +Or download the latest release manually from [GitHub](https://github.com/sendbird/SendBird-SDK-JavaScript) + + +## Getting Help + +Check out the [UIKit for React docs](https://sendbird.com/docs/uikit/v1/javascript/getting-started/about-uikit). and Sendbird's [Developer Portal](https://sendbird.com/developer) for tutorials and videos. If you need any help in resolving any issues or have questions, visit our [community forums](https://community.sendbird.com/c/sendbird-chat/12). + +## We are Hiring! +Sendbird is made up of a diverse group of humble, friendly, and hardworking individuals united by a shared purpose to build the next generation of mobile & social technologies. Join our team remotely or at one of our locations in San Mateo, Seoul, New York, London, and Singapore. More information on a [careers page](https://sendbird.com/careers). diff --git a/asset/reactnative-sample-thumbnail.jpg b/asset/reactnative-sample-thumbnail.jpg new file mode 100644 index 00000000..5e9ac8ec Binary files /dev/null and b/asset/reactnative-sample-thumbnail.jpg differ diff --git a/asset/uikit.png b/asset/uikit.png new file mode 100644 index 00000000..6f13c4c6 Binary files /dev/null and b/asset/uikit.png differ diff --git a/catalog-info.yaml b/catalog-info.yaml new file mode 100644 index 00000000..63286af8 --- /dev/null +++ b/catalog-info.yaml @@ -0,0 +1,12 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: sendbird-javascript-samples + description: A guide of the installation and functions of Sendbird Chat, UIKit, and SyncManager for JavaScript samples + annotations: + github.com/project-slug: sendbird/sendbird-javascript-samples +spec: + type: library + lifecycle: production + owner: dep-client-platform + system: sendbird-chat diff --git a/javascript/javascript-basic-local-caching/.babelrc b/javascript/javascript-basic-local-caching/.babelrc new file mode 100644 index 00000000..a7352030 --- /dev/null +++ b/javascript/javascript-basic-local-caching/.babelrc @@ -0,0 +1,8 @@ +{ + "presets": ["env"], + "env": { + "test": { + "presets": ["env"] + } + } +} diff --git a/javascript/javascript-basic-local-caching/.eslintignore b/javascript/javascript-basic-local-caching/.eslintignore new file mode 100644 index 00000000..feb309d8 --- /dev/null +++ b/javascript/javascript-basic-local-caching/.eslintignore @@ -0,0 +1,2 @@ + +**/*.min.js \ No newline at end of file diff --git a/javascript/javascript-basic-local-caching/.eslintrc.js b/javascript/javascript-basic-local-caching/.eslintrc.js new file mode 100644 index 00000000..0211a4b2 --- /dev/null +++ b/javascript/javascript-basic-local-caching/.eslintrc.js @@ -0,0 +1,21 @@ +module.exports = { + env: { + browser: true, + commonjs: true, + es6: true + }, + extends: 'eslint:recommended', + parserOptions: { + parser: 'babel-eslint', + sourceType: 'module' + }, + rules: { + 'linebreak-style': ['error', 'unix'], + quotes: ['warn', 'single'], + semi: ['warn', 'always'], + 'no-console': 1, + 'no-unused-vars': 1, + 'no-inner-declarations': 1, + 'no-useless-escape': 1 + } +}; diff --git a/javascript/javascript-basic-local-caching/.prettierignore b/javascript/javascript-basic-local-caching/.prettierignore new file mode 100644 index 00000000..52999c0b --- /dev/null +++ b/javascript/javascript-basic-local-caching/.prettierignore @@ -0,0 +1,2 @@ +README.md +.eslintrc.js \ No newline at end of file diff --git a/javascript/javascript-basic-local-caching/.prettierrc b/javascript/javascript-basic-local-caching/.prettierrc new file mode 100644 index 00000000..e90d7232 --- /dev/null +++ b/javascript/javascript-basic-local-caching/.prettierrc @@ -0,0 +1,6 @@ +{ + "singleQuote": true, + "printWidth": 120, + "trailingComma": "none", + "arrowParens": "avoid" +} \ No newline at end of file diff --git a/javascript/javascript-basic-local-caching/README.md b/javascript/javascript-basic-local-caching/README.md new file mode 100644 index 00000000..e06d3c33 --- /dev/null +++ b/javascript/javascript-basic-local-caching/README.md @@ -0,0 +1,81 @@ +# Sendbird Local Caching for JavaScript sample +![Platform](https://img.shields.io/badge/platform-JAVASCRIPT-orange.svg) +![Languages](https://img.shields.io/badge/language-JAVASCRIPT-orange.svg) +[![npm](https://img.shields.io/npm/v/sendbird.svg?style=popout&colorB=red)](https://www.npmjs.com/package/sendbird) + +## Introduction + +Local Caching enables Sendbird Chat SDK for JavaScript to locally cache and retrieve group channel and message data. This facilitates offline messaging by allowing the SDK to create a channel list view or a chat view in a prompt manner and display them even when a client app is in offline mode. Provided here is a Local Caching for JavaScript sample to experience first-hand the benefits of Sendbird's Local Caching. + +### Benefits + +Sendbird Local Caching provides the local caching system and data synchronization with the Sendbird server, which are run on an event-driven structure. According to the real-time events of the messages and channels, Local Caching takes care of the background tasks for the cache updates from the Sendbird server to the local device. By leveraging this systemized structure with connection-based synchronization, Local Caching allows you to easily integrate the Chat SDK to utilize all of its features, while also reducing data usage and offering a reliable and effortless storage mechanism. + +### More about Sendbird Local Caching for JavaScript + +Find out more about Sendbird Local Caching for JavaScript at [Local Caching for JavaScript doc](https://sendbird.com/docs/chat/v3/javascript/guides/local-caching). If you need any help in resolving any issues or have questions, visit [our community](https://community.sendbird.com). + +
+ +## Before getting started +This section provides the prerequisites for testing Sendbird Desk for JavaScript sample app. + +### Requirements +The minimum requirements for Local Caching for JavaScript are: +- Node.js v10+ +- NPM v6+ +- [Chat SDK for JavaScript](https://github.com/sendbird/SendBird-SDK-JavaScript) v3.1.0 or higher + +### Try the sample app using your data + +If you would like to try the sample app specifically fit to your usage, you can do so by replacing the default sample app ID with yours, which you can obtain by [creating your Sendbird application from the dashboard](https://sendbird.com/docs/chat/v3/javascript/getting-started/install-chat-sdk#2-step-1-create-a-sendbird-application-from-your-dashboard). Furthermore, you could also add data of your choice on the dashboard to test. This will allow you to experience the sample app with data from your Sendbird application. + +
+ +## Getting started + +You can install and run Local Caching for JavaScript sample app on your system using `npm`. + +### Install packages + +`Node` v8.x+ should be installed on your system. + +```bash +npm install +``` + +### Run the sample + +```bash +npm start +``` + +
+ +## Customizing the sample + +To implement customization to the sample, you can use `webpack` for buiding it. + +### Install packages + +`Node` v8.x+ should be installed on your system. + +```bash +npm install +``` + +### Modify files + +If you want to change `APP_ID`, change `APP_ID` in `const.js` to the other `APP_ID` you want. You can test the sample with local server by running the following command. + +```bash +npm run start:dev +``` + +### Build the sample + +When the modification is complete, you'll need to bundle the file using `webpack`. The bundled files are created in the **dist** folder. Please check `webpack.config.js` for settings. + +```bash +npm run build +``` diff --git a/javascript/javascript-basic-local-caching/chat.html b/javascript/javascript-basic-local-caching/chat.html new file mode 100644 index 00000000..00977a48 --- /dev/null +++ b/javascript/javascript-basic-local-caching/chat.html @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + Basic Sample with Local Caching | Sendbird + + + +
+
+
+ +
+ Sendbird +
+
+
+
+
GROUP CHAT
+
+
+
+
+
+
Start by inviting user to create a channel.
+
+
+
+
+ +
+
+
username
+
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/javascript/javascript-basic-local-caching/index.html b/javascript/javascript-basic-local-caching/index.html new file mode 100644 index 00000000..b9c984b8 --- /dev/null +++ b/javascript/javascript-basic-local-caching/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + Basic Sample with Local Caching | Sendbird + + + +
+
+ +
+
+ Sendbird +
+
+ Web Basic Sample with Local Caching +
+
+
+ +
+
+ Start chatting on Sendbird by choosing your display name. +
This can be changed anytime and will be shown on 1-on-1 and group messaging. + +
+
+ + + +
+
+ +
+ +
+
+ + + + diff --git a/javascript/javascript-basic-local-caching/migration.ts b/javascript/javascript-basic-local-caching/migration.ts new file mode 100644 index 00000000..adf743fc --- /dev/null +++ b/javascript/javascript-basic-local-caching/migration.ts @@ -0,0 +1,382 @@ +const sendbird = new SendBird({ appId: APP_ID }); + +const options = new SendBirdSyncManager.Options(); +options.messageCollectionCapacity = MESSAGE_COLLECTION_CAPACITY; +options.messageResendPolicy = MESSAGE_RESEND_POLICY; +options.automaticMessageResendRetryCount = AUTOMATIC_MESSAGE_RESEND_RETRY_COUNT; +options.maxFailedMessageCountPerChannel = MAX_FAILED_MESSAGE_COUNT_PER_CHANNEL; +options.failedMessageRetentionDays = FAILED_MESSAGE_RETENTION_DAYS; + +SendBirdSyncManager.sendbird = sendbird; +SendBirdSyncManager.setup(USER_ID, options, () => { + sendbird.setErrorFirstCallback(true); + sendbird + .connect(USER_ID) + .then(user => { + // Do something... + }) + .catch(error => { + // Handle error. + }); +}); + +const sendbird = new SendBird({ appId: APP_ID, localCacheEnabled: true }); +sendbird.setErrorFirstCallback(true); +sendbird + .connect(USER_ID) + .then(user => { + // Do something... + }) + .catch(error => { + // Handle error. + }); + +const myGroupChannelListQuery = sendbird.GroupChannel.createMyGroupChannelListQuery(); +myGroupChannelListQuery.includeEmpty = INCLUDE_EMPTY; +myGroupChannelListQuery.order = ORDER; +myGroupChannelListQuery.limit = LIMIT; + +const channelCollection = new SendBirdSyncManager.ChannelCollection(myGroupChannelListQuery); + +const groupChannelFilter = new sendbird.GroupChannelFilter(); +groupChannelFilter.includeEmpty = INCLUDE_EMPTY; + +const groupChannelCollection = sendbird.GroupChannel.createGroupChannelCollection() + .setOrder(ORDER) + .setFilter(FILTER) + .setLimit(LIMIT) + .build(); + +const collectionHandler = new SendBirdSyncManager.ChannelCollection.CollectionHandler(); +collectionHandler.onChannelEvent = (action, channels) => { + switch (action) { + case 'insert': + // Do something... + break; + case 'update': + // Do something... + break; + case 'move': + // Do something... + break; + case 'remove': + // Do something... + break; + case 'clear': + // Do something... + break; + } +}; +channelCollection.setCollectionHandler(collectionHandler); + +channelCollection.setGroupChannelCollectionHandler({ + onChannelsAdded: (context, channels) => { + // Do something... + }, + onChannelsUpdated: (context, channels) => { + // Do something... + }, + onChannelsDeleted: (context, channelUrls) => { + // Do something... + } +}); + +channelCollection.fetch(() => { + // Do something... +}); + +if (groupChannelCollection.hasMore) { + groupChannelCollection + .loadMore() + .then(channels => { + // Do something... + }) + .catch(error => { + // Handle error. + }); +} + +channelCollection.setCollectionHandler(null); +channelCollection.remove(); + +groupChannelCollection.dispose(); + +const messageFilter = { + messageTypeFilter: MESSAGE_TYPE_FILTER +}; +const messageCollection = new SendBirdSyncManager.MessageCollection(channel, messageFilter, STARTING_POINT); +messageCollection.limit = LIMIT; + +const messageFilter = new sendbird.MessageFilter(); +messageFilter.messageType = MESSAGE_TYPE; +const messageCollection = channel + .createMessageCollection() + .setFilter(messageFilter) + .setStartingPoint(STARTING_POINT) + .setLimit(LIMIT) + .build(); + +const messageCollectionHandler = new SendBirdSyncManager.MessageCollection.CollectionHandler(); +messageCollectionHandler.onPendingMessageEvent = (messages, action) => { + // Do something... +}; +messageCollectionHandler.onSucceededMessageEvent = (messages, action) => { + // Do something... +}; +messageCollectionHandler.onFailedMessageEvent = (messages, action, reason) => { + // Do something... +}; +messageCollectionHandler.onNewMessage = message => { + // Do something... +}; +messageCollectionHandler.onMessageEvent = (action, messages, action) => { + // Do something... +}; +messageCollectionHandler.onChannelUpdated = channel => { + // Do something... +}; +messageCollectionHandler.onChannelDeleted = channel => { + // Do something... +}; +messageCollection.setCollectionHandler(messageCollectionHandler); + +messageCollection.setMessageCollectionHandler({ + onMessagesAdded: (context, channel, messages) => { + // Do something... + }, + onMessagesUpdated: (context, channel, messages) => { + // Do something... + }, + onMessagesDeleted: (context, channel, messages) => { + // Do something... + }, + onChannelUpdated: (context, channel) => { + // Do something... + }, + onChannelDeleted: (context, channel) => { + // Do something... + }, + onHugeGapDetected: () => { + // Do something... + } +}); + +messageCollection + .initialize(MESSAGE_COLLECTION_INIT_POLICY) + .onCacheResult((error, messages) => { + if (error) { + // Handle error. + } + // Do something... + }) + .onApiResult((error, messages) => { + if (error) { + // Handle error. + } + // Do something... + }); + +messageCollection.fetchSucceededMessages('next', error => { + if (error) { + // Handle error; + } + // Do something... +}); + +if (messageCollection.hasNext) { + messageCollection + .loadNext() + .then(messages => { + // Do something... + }) + .catch(error => { + // Handle error. + }); +} + +messageCollection.fetchSucceededMessages('prev', error => { + if (error) { + // Handle error; + } + // Do something... +}); + +if (messageCollection.hasPrevious) { + messageCollection + .loadPrevious() + .then(messages => { + // Do something... + }) + .catch(error => { + // Handle error. + }); +} + +const pendingMessage = channel.sendUserMessage(USER_MESSAGE_PARAMS, (error, message) => { + messageCollection.handleSendMessageResponse(error, message); +}); +messageCollection.appendMessage(pendingMessage); + +channel.sendUserMessage(USER_MESSAGE_PARAMS, (error, message) => { + /** + * Pending message will be delivered to `MessageCollectionHandler.onMessagesAdded()`. + * The result of sending, either a succeeded or failed message, will be delivered to `MessageCollectionHandler.onMessagesUpdated()`. + * Do NOT add the pending, succeeded or failed message objects from the return value of `sendUserMessage()`, `sendFileMessage()`, and from the callback. + */ +}); + +const pendingMessage = channel.sendFileMessage(FILE_MESSAGE_PARAMS, (error, message) => { + messageCollection.handleSendMessageResponse(error, message); +}); +messageCollection.appendMessage(pendingMessage); + +channel.sendFileMessage(FILE_MESSAGE_PARAMS, (error, message) => { + /** + * Pending message will be delivered to `MessageCollectionHandler.onMessagesAdded()`. + * The result of sending, either a succeeded or failed message, will be delivered to `MessageCollectionHandler.onMessagesUpdated()`. + * Do NOT add the pending, succeeded or failed message objects from the return value of `sendUserMessage()`, `sendFileMessage()`, and from the callback. + */ +}); + +const pendingMessage = channel.resendUserMessage(failedMessage, (error, message) => { + messageCollection.handleSendMessageResponse(error, message); +}); +messageCollection.appendMessage(pendingMessage); + +channel.resendUserMessage(failedMessage, (error, message) => { + /** + * Pending message will be delivered to `MessageCollectionHandler.onMessagesUpdated()`. + * The result of sending, either a succeeded or failed message, will be delivered to `MessageCollectionHandler.onMessagesUpdated()`. + * Do NOT add the pending, succeeded or failed message objects from the return value of `resendUserMessage()`, `resendFileMessage()`, and from the callback. + */ +}); + +const pendingMessage = channel.resendFileMessage(failedMessage, (error, message) => { + messageCollection.handleSendMessageResponse(error, message); +}); +messageCollection.appendMessage(pendingMessage); + +channel.resendFileMessage(failedMessage, (error, message) => { + /** + * Pending message will be delivered to `MessageCollectionHandler.onMessagesUpdated()`. + * The result of sending, either a succeeded or failed message, will be delivered to `MessageCollectionHandler.onMessagesUpdated()`. + * Do NOT add the pending, succeeded or failed message objects from the return value of `resendUserMessage()`, `resendFileMessage()`, and from the callback. + */ +}); + +messageCollection.setCollectionHandler(null); +messageCollection.remove(); + +messageCollection.dispose(); + +messageCollectionHandler.onNewMessage = message => { + // Do something... +}; + +const channelHandler = new sendbird.ChannelHandler(); +channelHandler.onMessageReceived = (channel, message) => { + // Do something... +}; +sendbird.addChannelHandler(CHANNEL_HANDLER_KEY, channelHandler); + +channel.updateUserMessage(message.messageId, USER_MESSAGE_PARAMS, (error, message) => { + messageCollection.updateMessage(message); +}); + +channel.updateUserMessage(message.messageId, USER_MESSAGE_PARAMS, (error, message) => { + /** + * Updated message will be handled internally and will be delivered to `MessageCollectionHandler.onMessagesUpdated()`. + */ +}); + +channel.deleteMessage(message, error => { + messageCollection.deleteMessage(message); +}); + +channel.deleteMessage(message, error => { + /** + * The result will be delivered to `MessageCollectionHandler.onMessagesDeleted()`. + */ +}); + +messageCollection.deleteMessage(failedMessage); + +messageCollection + .removeFailedMessages(failedMessages) + .then(requestIds => { + // Do something... + }) + .catch(error => { + // Handle error. + }); + +messageCollection + .removeAllFailedMessages() + .then(() => { + // Do something... + }) + .catch(error => { + // Handle error. + }); + +messageCollection.resetViewpointTimestamp(TIMESTAMP); + +messageCollection.dispose(); +messageCollection = channel + .createMessageCollection() + .setFilter(messageFilter) + .setStartingPoint(messageCollection.startingPoint) + .setLimit(LIMIT) + .build(); +messageCollection + .initialize(MESSAGE_COLLECTION_INIT_POLICY) + .onCacheResult((error, messages) => { + if (error) { + // Handle error. + } + // Do something... + }) + .onApiResult((error, messages) => { + if (error) { + // Handle error. + } + // Do something... + }); + +messageCollection.fetchPendingMessages(error => { + if (error) { + // Handle error; + } + // Do something... +}); + +const pendingMessages = messageCollection.pendingMessages; + +messageCollection.fetchFailedMessages(error => { + if (error) { + // Handle error; + } + // Do something... +}); + +const failedMessages = messageCollection.failedMessages; + +const messageCount = messageCollection.messageCount; + +const messageCount = messageCollection.succeededMessages.length; + +SendBirdSyncManager.getInstance().clearCache(error => { + if (error) { + // Handle error. + } + // Do something... +}); + +sendbird + .clearCachedMessages(CHANNEL_URLS) + .then(() => { + // Do something... + }) + .catch(error => { + // Handle error. + }); diff --git a/javascript/javascript-basic-local-caching/package.json b/javascript/javascript-basic-local-caching/package.json new file mode 100644 index 00000000..ac1db3c9 --- /dev/null +++ b/javascript/javascript-basic-local-caching/package.json @@ -0,0 +1,39 @@ +{ + "name": "sendbird-sample-javascript-local-caching", + "version": "1.0.0", + "description": "Sendbird Sample using Local Caching", + "main": "index.js", + "scripts": { + "dev": "./node_modules/.bin/webpack --mode=development", + "dev:w": "./node_modules/.bin/webpack --mode=none -w", + "build": "./node_modules/.bin/webpack --mode=production", + "start:dev": "./node_modules/.bin/webpack-dev-server", + "start": "npm run build && node server.js", + "deploy": "node ./deploy/deploy.js" + }, + "author": "Sendbird", + "license": "ISC", + "devDependencies": { + "babel-core": "^6.26.0", + "babel-eslint": "^8.2.3", + "babel-loader": "^7.1.4", + "babel-preset-env": "^1.6.1", + "css-loader": "^0.28.11", + "eslint": "^4.19.1", + "eslint-loader": "^2.1.1", + "express": "^4.16.3", + "extract-text-webpack-plugin": "^4.0.0-beta.0", + "prettier": "^1.14.3", + "sass": "^1.49.9", + "sass-loader": "^10", + "ssh2": "^0.8.5", + "style-loader": "^0.21.0", + "webpack": "^4.19.1", + "webpack-cli": "^3.1.0", + "webpack-dev-server": "^3.1.11" + }, + "dependencies": { + "moment": "^2.22.1", + "sendbird": "^3.1.1" + } +} diff --git a/javascript/javascript-basic-local-caching/server.js b/javascript/javascript-basic-local-caching/server.js new file mode 100644 index 00000000..487ba47b --- /dev/null +++ b/javascript/javascript-basic-local-caching/server.js @@ -0,0 +1,14 @@ +const express = require('express'); +const app = express(); + +const PORT = 9000; + +app.use(express.static('dist')); +app.use(express.static('./')); + +app.get('/', function(req, res) { + res.sendfile('index.html'); +}); + +app.listen(PORT); +console.log(`[SERVER RUNNING] 127.0.0.1:${PORT}`); diff --git a/javascript/javascript-basic-local-caching/src/js/Chat.js b/javascript/javascript-basic-local-caching/src/js/Chat.js new file mode 100644 index 00000000..ee82c7ca --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/Chat.js @@ -0,0 +1,120 @@ +import styles from '../scss/chat.scss'; +import { createDivEl } from './utils'; +import { SendBirdAction } from './SendBirdAction'; +import { SendBirdChatEvent } from './SendBirdChatEvent'; +import { ChatLeftMenu } from './ChatLeftMenu'; +import { ChatTopMenu } from './components/ChatTopMenu'; +import { ChatMain } from './components/ChatMain'; + +let instance = null; + +class Chat { + constructor() { + if (instance) { + return instance; + } + this.body = document.querySelector('.body-center'); + + this.channel = null; + this.element = null; + this.top = null; + this.emptyElement = this._createEmptyElement(); + this.render(); + instance = this; + } + + _createEmptyElement() { + const item = createDivEl({ className: styles['chat-empty'] }); + + const content = createDivEl({ className: styles['empty-content'] }); + item.appendChild(content); + + const title = createDivEl({ className: styles['content-title'], content: 'WELCOME TO SAMPLE CHAT' }); + content.appendChild(title); + const image = createDivEl({ className: styles['content-image'] }); + content.appendChild(image); + const desc = createDivEl({ + className: styles['content-desc'], + content: + 'Create or select a channel to chat in.\n' + + "If you don't have a channel to participate,\n" + + 'go ahead and create your first channel now.' + }); + content.appendChild(desc); + return item; + } + + renderEmptyElement() { + this._removeChatElement(); + this.body.appendChild(this.emptyElement); + } + + _removeEmptyElement() { + if (this.body.contains(this.emptyElement)) { + this.body.removeChild(this.emptyElement); + } + } + + _createChatElement(channel) { + this.element = createDivEl({ className: styles['chat-root'] }); + + this.top = new ChatTopMenu(channel); + this.element.appendChild(this.top.element); + + /// reset manager when ChatMain is obsolete + if (this.main && this.main.body && this.main.body.collection) { + this.main.body.collection.dispose(); + } + this.main = new ChatMain(channel); + } + + _addEventHandler() { + const channelEvent = new SendBirdChatEvent(); + channelEvent.onTypingStatusUpdated = groupChannel => { + if (this.channel.url === groupChannel.url) { + this.main.updateTyping(groupChannel.getTypingMembers()); + } + }; + } + + _renderChatElement(channel) { + const sendbirdAction = SendBirdAction.getInstance(); + this._removeEmptyElement(); + this._removeChatElement(); + this.channel = channel; + + ChatLeftMenu.getInstance().activeChannelItem(channel.url); + this._addEventHandler(); + + sendbirdAction + .getChannel(channel.url) + .then(channel => { + this.channel = channel; + this._createChatElement(this.channel); + this.body.appendChild(this.element); + this.main.loadInitialMessages(); + }) + .catch(() => { + this._createChatElement(this.channel); + this.body.appendChild(this.element); + this.main.loadInitialMessages(); + }); + } + + _removeChatElement() { + const chatElements = this.body.getElementsByClassName(styles['chat-root']); + Array.prototype.slice.call(chatElements).forEach(chatEl => { + chatEl.parentNode.removeChild(chatEl); + }); + } + + render(channel) { + channel ? this._renderChatElement(channel) : this.renderEmptyElement(); + } + + static getInstance() { + return new Chat(); + } +} + +export { Chat }; diff --git a/javascript/javascript-basic-local-caching/src/js/ChatLeftMenu.js b/javascript/javascript-basic-local-caching/src/js/ChatLeftMenu.js new file mode 100644 index 00000000..27707918 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/ChatLeftMenu.js @@ -0,0 +1,144 @@ +import { LeftListItem } from './components/LeftListItem'; +import { ACTIVE_CLASSNAME, DISPLAY_BLOCK, DISPLAY_NONE } from './const'; +import { addClass, isScrollBottom, isUrl, protectFromXSS, removeClass, findChannelIndex } from './utils'; +import { SendBirdAction } from './SendBirdAction'; +import { UserList } from './components/UserList'; +import { Chat } from './Chat'; + +let instance = null; + +class ChatLeftMenu { + constructor() { + if (instance) { + return instance; + } + this.activeChannelUrl = null; + + const action = new SendBirdAction(); + const sb = action.sb; + const groupChannelFilter = new sb.GroupChannelFilter(); + groupChannelFilter.includeEmpty = false; + this.channelCollection = sb.GroupChannel.createGroupChannelCollection() + .setOrder(sb.GroupChannelCollection.GroupChannelOrder.ORDER_LATEST_LAST_MESSAGE) + .setFilter(groupChannelFilter) + .setLimit(50) + .build(); + this.channelCollection.setGroupChannelCollectionHandler({ + onChannelsAdded: (context, channels) => { + for (let i in channels) { + const channel = channels[i]; + const index = findChannelIndex(channel, this.channelCollection.channels); + const handler = () => { + Chat.getInstance().render(channel, false); + this.activeChannelUrl = channel.url; + }; + const item = new LeftListItem({ channel, handler }); + if (index < this.groupChannelList.childNodes.length - 1) { + this.groupChannelList.insertBefore(item.element, this.groupChannelList.childNodes[index]); + } else { + this.groupChannelList.appendChild(item.element); + } + if (this.activeChannelUrl === channel.url) { + this.activeChannelItem(channel.url); + } + } + LeftListItem.updateUnreadCount(); + this.toggleGroupChannelDefaultItem(); + }, + onChannelsUpdated: (context, channels) => { + for (let i in channels) { + const channel = channels[i]; + const item = this.getItem(channel.url); + const handler = () => { + Chat.getInstance().render(channel, false); + this.activeChannelUrl = channel.url; + }; + const newItem = new LeftListItem({ channel, handler }); + this.groupChannelList.replaceChild(newItem.element, item); + if (this.activeChannelUrl === channel.url) { + this.activeChannelItem(channel.url); + } + } + LeftListItem.updateUnreadCount(); + }, + onChannelsDeleted: (context, channelUrls) => { + for (let i in channelUrls) { + const channelUrl = channelUrls[i]; + if (this.activeChannelUrl === channelUrl) { + this.activeChannelUrl = null; + Chat.getInstance().render(); + } + const element = this.getItem(channelUrl); + this.groupChannelList.removeChild(element); + } + this.toggleGroupChannelDefaultItem(); + } + }); + + this.groupChannelList = document.getElementById('group_list'); + this.groupChannelList.addEventListener('scroll', () => { + if (isScrollBottom(this.groupChannelList)) { + this.loadGroupChannelList(); + } + }); + this.groupChannelDefaultItem = document.getElementById('default_item_group'); + + const groupChannelCreateBtn = document.getElementById('group_chat_add'); + groupChannelCreateBtn.addEventListener('click', () => { + UserList.getInstance().render(); + }); + instance = this; + } + + updateUserInfo(user) { + const userInfoEl = document.getElementById('user_info'); + const profileEl = userInfoEl.getElementsByClassName('image-profile')[0]; + if (isUrl(user.profileUrl)) { + profileEl.setAttribute('src', protectFromXSS(user.profileUrl)); + } + const nicknameEl = userInfoEl.getElementsByClassName('nickname-content')[0]; + nicknameEl.innerHTML = protectFromXSS(user.nickname); + } + + loadGroupChannelList() { + this.channelCollection.loadMore().then(channels => { + for (let channel of channels) { + const handler = () => { + Chat.getInstance().render(channel, false); + this.activeChannelUrl = channel.url; + }; + const item = new LeftListItem({ channel, handler }); + this.groupChannelList.appendChild(item.element); + } + this.toggleGroupChannelDefaultItem(); + }); + } + getItem(elementId) { + const groupChannelItems = this.groupChannelList.getElementsByClassName(LeftListItem.getItemRootClassName()); + for (let i = 0; i < groupChannelItems.length; i++) { + if (groupChannelItems[i].id === elementId) { + return groupChannelItems[i]; + } + } + return null; + } + activeChannelItem(channelUrl) { + const groupItems = this.groupChannelList.getElementsByClassName(LeftListItem.getItemRootClassName()); + for (let i = 0; i < groupItems.length; i++) { + groupItems[i].id === channelUrl + ? addClass(groupItems[i], ACTIVE_CLASSNAME) + : removeClass(groupItems[i], ACTIVE_CLASSNAME); + } + } + toggleGroupChannelDefaultItem() { + this.groupChannelList.getElementsByClassName(LeftListItem.getItemRootClassName()).length > 0 + ? (this.groupChannelDefaultItem.style.display = DISPLAY_NONE) + : (this.groupChannelDefaultItem.style.display = DISPLAY_BLOCK); + } + + static getInstance() { + return new ChatLeftMenu(); + } +} + +export { ChatLeftMenu }; diff --git a/javascript/javascript-basic-local-caching/src/js/SendBirdAction.js b/javascript/javascript-basic-local-caching/src/js/SendBirdAction.js new file mode 100644 index 00000000..826bbe31 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/SendBirdAction.js @@ -0,0 +1,237 @@ +import { APP_ID as appId } from './const'; +import { isNull } from './utils'; + +import SendBird from 'sendbird'; + +let instance = null; + +class SendBirdAction { + constructor() { + if (instance) { + return instance; + } + this.sb = new SendBird({ + appId, + localCacheEnabled: true + }); + this.sb.setErrorFirstCallback(true); + this.userQuery = null; + this.groupChannelQuery = null; + this.previousMessageQuery = null; + this.blockedQuery = null; + instance = this; + } + + /** + * Connect + */ + connect(userId, nickname) { + return new Promise((resolve, reject) => { + const sb = SendBird.getInstance(); + sb.connect(userId, (error, user) => { + if (error) { + reject(error); + } else { + sb.updateCurrentUserInfo(decodeURIComponent(nickname), null, (error, user) => { + error ? reject(error) : resolve(user); + }); + } + }); + }); + } + + /** + * User + */ + getCurrentUser() { + return this.sb.currentUser; + } + + getConnectionState() { + return this.sb.getConnectionState(); + } + + /** + * + * #################### SECURITY TIPS #################### + * Before launching, you should review "Allow retrieving user list from SDK" under ⚙️ Sendbird Dashboard ->Settings -> Security. + * It's turned on at first to simplify running samples and implementing your first code. + * Most apps will want to disable "Allow retrieving user list from SDK" as that could possibly expose user information + * #################### SECURITY TIPS #################### + * + */ + getUserList(isInit = false) { + if (isInit || isNull(this.userQuery)) { + this.userQuery = this.sb.createApplicationUserListQuery(); + this.userQuery.limit = 30; + } + return new Promise((resolve, reject) => { + if (this.userQuery.hasNext && !this.userQuery.isLoading) { + this.userQuery.next((error, list) => { + error ? reject(error) : resolve(list); + }); + } else { + resolve([]); + } + }); + } + + isCurrentUser(user) { + return user.userId === this.sb.currentUser.userId; + } + + getBlockedList(isInit = false) { + if (isInit || isNull(this.blockedQuery)) { + this.blockedQuery = this.sb.createBlockedUserListQuery(); + this.blockedQuery.limit = 30; + } + return new Promise((resolve, reject) => { + if (this.blockedQuery.hasNext && !this.blockedQuery.isLoading) { + this.blockedQuery.next((error, blockedList) => { + error ? reject(error) : resolve(blockedList); + }); + } else { + resolve([]); + } + }); + } + + blockUser(user, isBlock = true) { + return new Promise((resolve, reject) => { + if (isBlock) { + this.sb.blockUser(user, (error, response) => { + error ? reject(error) : resolve(); + }); + } else { + this.sb.unblockUser(user, (error, response) => { + error ? reject(error) : resolve(); + }); + } + }); + } + + /** + * Channel + */ + getChannel(channelUrl) { + return new Promise((resolve, reject) => { + this.sb.GroupChannel.getChannel(channelUrl, (error, groupChannel) => { + error ? reject(error) : resolve(groupChannel); + }); + }); + } + + /** + * + * #################### SECURITY TIPS #################### + * Before launching, you should review "Allow creating group channels from SDK" under ⚙️ Sendbird Dashboard -> Settings -> Security. + * It's turned on at first to simplify running samples and implementing your first code. + * Most apps will want to disable "Allow creating group channels from SDK" as that could cause unwanted operations. + * #################### SECURITY TIPS #################### + * + */ + createGroupChannel(userIds) { + return new Promise((resolve, reject) => { + let params = new this.sb.GroupChannelParams(); + params.addUserIds(userIds); + this.sb.GroupChannel.createChannel(params, (error, groupChannel) => { + error ? reject(error) : resolve(groupChannel); + }); + }); + } + + inviteGroupChannel(channelUrl, userIds) { + return new Promise((resolve, reject) => { + this.sb.GroupChannel.getChannel(channelUrl, (error, groupChannel) => { + if (error) { + reject(error); + } else { + groupChannel.inviteWithUserIds(userIds, (error, groupChannel) => { + error ? reject(error) : resolve(groupChannel); + }); + } + }); + }); + } + + leave(channelUrl) { + return new Promise((resolve, reject) => { + this.sb.GroupChannel.getChannel(channelUrl, (error, groupChannel) => { + if (error) { + reject(error); + } else { + groupChannel.leave((error, response) => { + error ? reject(error) : resolve(); + }); + } + }); + }); + } + + hide(channelUrl) { + return new Promise((resolve, reject) => { + this.sb.GroupChannel.getChannel(channelUrl, (error, groupChannel) => { + if (error) { + reject(error); + } else { + groupChannel.hide((error, response) => { + error ? reject(error) : resolve(); + }); + } + }); + }); + } + + markAsRead(channel) { + channel.markAsRead(); + } + + getReadReceipt(channel, message) { + if (this.isCurrentUser(message.sender)) { + return this.sb.currentUser ? channel.getReadReceipt(message) : 0; + } else { + return 0; + } + } + + sendUserMessage({ channel, message, handler }) { + return channel.sendUserMessage(message, (error, message) => { + if (handler) handler(error, message); + }); + } + + sendFileMessage({ channel, file, thumbnailSizes, handler }) { + const fileMessageParams = new this.sb.FileMessageParams(); + fileMessageParams.file = file; + fileMessageParams.thumbnailSizes = thumbnailSizes; + + return channel.sendFileMessage(fileMessageParams, (error, message) => { + if (handler) handler(error, message); + }); + } + + deleteMessage({ channel, message, col }) { + return new Promise((resolve, reject) => { + if (!this.isCurrentUser(message.sender)) { + reject({ + message: 'You have not ownership in this message.' + }); + return; + } + if (message.messageId === 0 && (message.sendingStatus === 'pending' || message.sendingStatus === 'failed')) { + col.deleteMessage(message); + resolve(true); + } else { + channel.deleteMessage(message, (error, response) => { + error ? reject(error) : resolve(response); + }); + } + }); + } + + static getInstance() { + return new SendBirdAction(); + } +} + +export { SendBirdAction }; diff --git a/javascript/javascript-basic-local-caching/src/js/SendBirdChatEvent.js b/javascript/javascript-basic-local-caching/src/js/SendBirdChatEvent.js new file mode 100644 index 00000000..8f12fd0e --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/SendBirdChatEvent.js @@ -0,0 +1,68 @@ +import { uuid4 } from './utils'; +import SendBird from 'sendbird'; + +let instance = null; + +class SendBirdChatEvent { + constructor() { + if (instance) { + return instance; + } + + this.sb = SendBird.getInstance(); + this.key = uuid4(); + this._createChannelHandler(); + + this.onMessageReceived = null; + this.onMessageUpdated = null; + this.onMessageDeleted = null; + + this.onReadReceiptUpdated = null; + this.onTypingStatusUpdated = null; + instance = this; + } + + /** + * Channel Handler + */ + _createChannelHandler() { + const handler = new this.sb.ChannelHandler(); + handler.onMessageReceived = (channel, message) => { + if (this.onMessageReceived) { + this.onMessageReceived(channel, message); + } + }; + handler.onMessageUpdated = (channel, message) => { + if (this.onMessageUpdated) { + this.onMessageUpdated(channel, message); + } + }; + handler.onMessageDeleted = (channel, messageId) => { + if (this.onMessageDeleted) { + this.onMessageDeleted(channel, messageId); + } + }; + + handler.onReadReceiptUpdated = groupChannel => { + if (this.onReadReceiptUpdated) { + this.onReadReceiptUpdated(groupChannel); + } + }; + handler.onTypingStatusUpdated = groupChannel => { + if (this.onTypingStatusUpdated) { + this.onTypingStatusUpdated(groupChannel); + } + }; + this.sb.addChannelHandler(this.key, handler); + } + + remove() { + this.sb.removeChannelHandler(this.key); + } + + static getInstance() { + return instance; + } +} + +export { SendBirdChatEvent }; diff --git a/javascript/javascript-basic-local-caching/src/js/SendBirdConnection.js b/javascript/javascript-basic-local-caching/src/js/SendBirdConnection.js new file mode 100644 index 00000000..5bda9b1a --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/SendBirdConnection.js @@ -0,0 +1,62 @@ +import { uuid4 } from './utils'; +import SendBird from 'sendbird'; +import { Chat } from './Chat'; + +let instance = null; + +class SendBirdConnection { + constructor() { + if (instance) { + return instance; + } + + this.sb = SendBird.getInstance(); + this.key = uuid4(); + this.channel = null; + this._createConnectionHandler(this.key); + this.chat = Chat.getInstance(); + + this.onReconnectStarted = null; + this.onReconnectSucceeded = null; + this.onReconnectFailed = null; + + instance = this; + } + + _createConnectionHandler(key) { + const handler = new this.sb.ConnectionHandler(); + handler.onReconnectStarted = () => { + if (this.chat && this.chat.main) { + this.chat.main.body.stopSpinner(); + } + if (this.onReconnectStarted) { + this.onReconnectStarted(); + } + }; + handler.onReconnectSucceeded = () => { + if (this.onReconnectSucceeded) { + this.onReconnectSucceeded(); + } + }; + handler.onReconnectFailed = () => { + if (this.onReconnectFailed) { + this.onReconnectFailed(); + } + }; + this.sb.addConnectionHandler(key, handler); + } + + remove() { + this.sb.removeConnectionHandler(this.key); + } + + reconnect() { + this.sb.reconnect(); + } + + static getInstance() { + return new SendBirdConnection(); + } +} + +export { SendBirdConnection }; diff --git a/javascript/javascript-basic-local-caching/src/js/SendBirdEvent.js b/javascript/javascript-basic-local-caching/src/js/SendBirdEvent.js new file mode 100644 index 00000000..58c82969 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/SendBirdEvent.js @@ -0,0 +1,47 @@ +import { uuid4 } from './utils'; +import SendBird from 'sendbird'; + +class SendBirdEvent { + constructor() { + this.sb = SendBird.getInstance(); + this.key = uuid4(); + this._createChannelHandler(); + + this.onChannelChanged = null; + this.onUserJoined = null; + this.onUserLeft = null; + this.onChannelHidden = null; + this.onUserEntered = null; + } + + _createChannelHandler() { + const handler = new this.sb.ChannelHandler(); + handler.onChannelChanged = channel => { + if (this.onChannelChanged) { + this.onChannelChanged(channel); + } + }; + handler.onUserJoined = (groupChannel, user) => { + if (this.onUserJoined) { + this.onUserJoined(groupChannel, user); + } + }; + handler.onUserLeft = (groupChannel, user) => { + if (this.onUserLeft) { + this.onUserLeft(groupChannel, user); + } + }; + handler.onChannelHidden = groupChannel => { + if (this.onChannelHidden) { + this.onChannelHidden(groupChannel); + } + }; + this.sb.addChannelHandler(this.key, handler); + } + + remove() { + this.sb.removeChannelHandler(this.key); + } +} + +export { SendBirdEvent }; diff --git a/javascript/javascript-basic-local-caching/src/js/components/ChatBody.js b/javascript/javascript-basic-local-caching/src/js/components/ChatBody.js new file mode 100644 index 00000000..e96efcf9 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/components/ChatBody.js @@ -0,0 +1,247 @@ +import styles from '../../scss/chat-body.scss'; +import { createDivEl, getDataInElement, removeClass, findMessageIndex, mergeFailedWithSuccessful } from '../utils'; +import { Message } from './Message'; +import { SendBirdAction } from '../SendBirdAction'; +import { MESSAGE_REQ_ID } from '../const'; +import { Spinner } from './Spinner'; + +class ChatBody { + constructor(channel) { + this.channel = channel; + this.readReceiptManageList = []; + this.scrollHeight = 0; + this.collection = null; + this.limit = 50; + this.element = createDivEl({ className: styles['chat-body'] }); + this._initElement(); + this.spinnerStarted = false; + this.messagesView = []; + } + + _initElement() { + if (this.collection) { + this.collection.dispose(); + } + const action = SendBirdAction.getInstance(); + const sb = action.sb; + const messageFilter = new sb.MessageFilter(); + this.collection = this.channel + .createMessageCollection() + .setFilter(messageFilter) + .setStartingPoint(new Date().getTime()) + .setLimit(this.limit) + .build(); + + this.collection.setMessageCollectionHandler({ + onMessagesAdded: (context, channel, messages) => { + this._mergeMessagesOnInsert(messages); + }, + onMessagesUpdated: (context, channel, messages) => { + this._updateMessages(messages); + }, + onMessagesDeleted: (context, channel, messages) => { + this._removeMessages(messages); + }, + onChannelUpdated: (context, channel) => {}, + onChannelDeleted: (context, channel) => {}, + onHugeGapDetected: () => {} + }); + + this.element.addEventListener('scroll', () => { + if (this.element.scrollTop === 0) { + this.updateCurrentScrollHeight(); + this.collection.loadPrevious().then(messages => { + this.element.scrollTop = this.element.scrollHeight - this.scrollHeight; + }); + } + + if (this.element.scrollHeight - this.element.scrollTop - this.element.clientHeight === 0) { + const newMessagePop = document.getElementById('new-message-pop'); + if (newMessagePop) newMessagePop.remove(); + } + }); + } + + _mergeMessagesOnInsert(messages) { + const { pendingMessages, succeededMessages, failedMessages } = this.collection; + const wholeCollectionMessages = [...pendingMessages, ...succeededMessages, ...failedMessages]; + wholeCollectionMessages.sort((message1, message2) => { + if (message1.messageId !== 0 && message2.messageId !== 0) { + return message1.messageId - message2.messageId; + } else if (message1.reqId && message2.reqId) { + return parseInt(message1.reqId) - parseInt(message2.reqId); + } + return message1.createdAt - message2.createdAt; + }); + for (let message of messages) { + const index = findMessageIndex(message, wholeCollectionMessages); + if (index >= 0) { + const messageElements = this.element.querySelectorAll('.chat-message'); + const messageItem = new Message({ channel: this.channel, message, col: this.collection }); + this.element.insertBefore(messageItem.element, messageElements[index]); + if ( + (message.isUserMessage() || message.isFileMessage()) && + SendBirdAction.getInstance().isCurrentUser(message.sender) + ) { + this.readReceiptManage(message); + } + } + } + } + + _updateMessages(messages, transformToManual = false) { + for (let i in messages) { + const message = messages[i]; + const messageItem = new Message({ + channel: this.channel, + message, + isManual: transformToManual, + col: this.collection + }); + const currentItem = this._getItem(message.reqId); + const requestItem = message.reqId ? this._getItem(message.reqId) : null; + if (currentItem || requestItem) { + this.element.replaceChild(messageItem.element, requestItem ? requestItem : currentItem); + } + } + } + + _removeMessages(messages) { + if ( + this.collection.pendingMessages.length > 0 && + messages.length > 0 && + messages[0].messageId === 0 && + !this.spinnerStarted + ) { + const el = this._getItem(messages[0].reqId); + const resendButton = el.firstChild.getElementsByClassName('resend-button'); + if (resendButton && resendButton.length === 0) { + Spinner.start(this.element); + this.spinnerStarted = true; + } + } + for (let i in messages) { + const message = messages[i]; + this.removeMessage(message.reqId); + } + if ( + (this.spinnerStarted && this.collection.pendingMessages.length === 0) || + SendBirdAction.getInstance().getConnectionState() !== 'OPEN' + ) { + this.stopSpinner(); + } + } + + stopSpinner() { + Spinner.remove(); + this.spinnerStarted = false; + } + + _clearMessages() { + while (this.element.firstChild) { + this.element.removeChild(this.element.firstChild); + } + } + + loadPreviousMessages(callback) { + this.collection.loadPrevious().then(messages => { + this._mergeMessagesOnInsert(messages); + callback(); + }); + } + + loadInitialMessages(callback) { + const action = SendBirdAction.getInstance(); + const sb = action.sb; + this.collection + .initialize(sb.MessageCollection.MessageCollectionInitPolicy.CACHE_AND_REPLACE_BY_API, new Date().getTime()) + .onCacheResult((error, messages) => { + if (!error) { + this._mergeMessagesOnInsert(messages); + } + }) + .onApiResult((error, messages) => { + if (!error) { + this.element.innerHTML = ''; + this._mergeMessagesOnInsert(messages); + } + callback(); + }); + } + + scrollToBottom() { + this.element.scrollTop = this.element.scrollHeight - this.element.offsetHeight; + } + + updateCurrentScrollHeight() { + this.scrollHeight = this.element.scrollHeight; + } + + repositionScroll(imageOffsetHeight) { + this.element.scrollTop += imageOffsetHeight; + } + + updateReadReceipt() { + this.readReceiptManageList.forEach(message => { + if (message.messageId.toString() !== '0') { + const className = Message.getReadReceiptElementClassName(); + const messageItem = this._getItem(message.reqId); + if (messageItem) { + let readItem = null; + try { + readItem = messageItem.getElementsByClassName(className)[0]; + } catch (e) { + readItem = null; + } + const latestCount = SendBirdAction.getInstance().getReadReceipt(this.channel, message); + if (readItem && latestCount.toString() !== readItem.textContent.toString()) { + readItem.innerHTML = latestCount; + if (latestCount.toString() === '0') { + removeClass(readItem, className); + } + } + } + } + }); + } + + readReceiptManage(message) { + for (let i = 0; i < this.readReceiptManageList.length; i++) { + if (message.reqId) { + if (this.readReceiptManageList[i].reqId === message.reqId) { + this.readReceiptManageList.splice(i, 1); + break; + } + } else { + if (this.readReceiptManageList[i].messageId === message.messageId) { + this.readReceiptManageList.splice(i, 1); + break; + } + } + } + this.readReceiptManageList.push(message); + this.updateReadReceipt(); + } + + _getItem(reqId) { + const items = this.element.childNodes; + // We go in reverse order to prevent situations that + // pending-message remove requests accidentally delete succeeded messages + for (let i = items.length - 1; i >= 0; i--) { + const elementId = getDataInElement(items[i], MESSAGE_REQ_ID); + if (elementId === reqId.toString()) { + return items[i]; + } + } + return null; + } + + removeMessage(reqId) { + const removeElement = this._getItem(reqId); + if (removeElement) { + this.element.removeChild(removeElement); + } + } +} + +export { ChatBody }; diff --git a/javascript/javascript-basic-local-caching/src/js/components/ChatInput.js b/javascript/javascript-basic-local-caching/src/js/components/ChatInput.js new file mode 100644 index 00000000..da23c486 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/components/ChatInput.js @@ -0,0 +1,116 @@ +import styles from '../../scss/chat-input.scss'; +import { createDivEl, protectFromXSS } from '../utils'; +import { DISPLAY_BLOCK, DISPLAY_NONE, FILE_ID, KEY_ENTER } from '../const'; +import { SendBirdAction } from '../SendBirdAction'; +import { Chat } from '../Chat'; + +class ChatInput { + constructor(channel) { + this.channel = channel; + this.input = null; + this.typing = null; + this.element = this._createElement(channel); + } + + _createElement(channel) { + const sendbirdAction = SendBirdAction.getInstance(); + const chat = Chat.getInstance(); + const root = createDivEl({ className: styles['chat-input'] }); + + this.typing = createDivEl({ className: styles['typing-field'] }); + root.appendChild(this.typing); + + const file = document.createElement('label'); + file.className = styles['input-file']; + file.for = FILE_ID; + file.addEventListener('click', () => { + sendbirdAction.markAsRead(this.channel); + }); + + const fileInput = document.createElement('input'); + fileInput.type = 'file'; + fileInput.id = FILE_ID; + fileInput.style.display = DISPLAY_NONE; + fileInput.addEventListener('change', () => { + const sendFile = fileInput.files[0]; + if (sendFile) { + const previewMessage = SendBirdAction.getInstance().sendFileMessage({ + channel: this.channel, + file: sendFile, + thumbnailSizes: [ + { maxWidth: 240, maxHeight: 240 }, + { maxWidth: 320, maxHeight: 320 } + ], + handler: (error, message) => { + chat.main.body.scrollToBottom(); + } + }); + previewMessage.createdAt = new Date().getTime(); + } + }); + + file.appendChild(fileInput); + root.appendChild(file); + + const inputText = createDivEl({ className: styles['input-text'] }); + + this.input = document.createElement('textarea'); + this.input.className = styles['input-text-area']; + this.input.placeholder = 'Write a chat...'; + this.input.addEventListener('click', () => { + sendbirdAction.markAsRead(this.channel); + }); + this.input.addEventListener('keypress', e => { + if (e.keyCode === KEY_ENTER) { + if (!e.shiftKey) { + e.preventDefault(); + const message = this.input.value; + this.input.value = ''; + if (message) { + const previewMessage = SendBirdAction.getInstance().sendUserMessage({ + channel: this.channel, + message, + handler: (error, message) => { + chat.main.body.scrollToBottom(); + } + }); + channel.endTyping(); + } + } else { + channel.startTyping(); + } + } else { + channel.startTyping(); + } + }); + this.input.addEventListener('focusin', () => { + inputText.style.border = '1px solid #2C2D30'; + }); + this.input.addEventListener('focusout', () => { + inputText.style.border = ''; + }); + + inputText.appendChild(this.input); + root.appendChild(inputText); + return root; + } + + updateTyping(memberList) { + let nicknames = ''; + if (memberList.length === 1) { + nicknames = `${protectFromXSS(memberList[0].nickname)} is`; + } else if (memberList.length === 2) { + nicknames = `${memberList + .map(member => { + return protectFromXSS(member.nickname); + }) + .join(', ')} are`; + } else if (memberList.length !== 0) { + nicknames = 'Several are'; + } + this.typing.style.display = nicknames ? DISPLAY_BLOCK : DISPLAY_NONE; + this.typing.innerHTML = `${nicknames} typing...`; + } +} + +export { ChatInput }; diff --git a/javascript/javascript-basic-local-caching/src/js/components/ChatMain.js b/javascript/javascript-basic-local-caching/src/js/components/ChatMain.js new file mode 100644 index 00000000..8d323d98 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/components/ChatMain.js @@ -0,0 +1,59 @@ +import styles from '../../scss/chat-main.scss'; +import { ChatBody } from './ChatBody'; +import { ChatInput } from './ChatInput'; +import { Chat } from '../Chat'; +import { createDivEl } from '../utils'; +import { ChatMenu } from './ChatMenu'; +import { SendBirdAction } from '../SendBirdAction'; + +class ChatMain { + constructor(channel) { + this.channel = channel; + this.body = null; + this.input = null; + this.menu = null; + this._create(); + } + + _create() { + const root = createDivEl({ className: styles['chat-main-root'] }); + + const main = createDivEl({ className: styles['chat-main'] }); + root.appendChild(main); + + this.body = new ChatBody(this.channel); + main.appendChild(this.body.element); + + this.input = new ChatInput(this.channel); + main.appendChild(this.input.element); + + this.menu = new ChatMenu(this.channel); + root.appendChild(this.menu.element); + + Chat.getInstance().element.appendChild(root); + } + + updateTyping(memberList) { + this.input.updateTyping(memberList); + } + + repositionScroll(height) { + this.body.repositionScroll(height); + } + + updateBlockedList(user, isBlock) { + this.menu.updateBlockedList(user, isBlock); + } + + loadInitialMessages() { + const sendbirdAction = SendBirdAction.getInstance(); + this.body.loadInitialMessages(() => { + this.body.loadPreviousMessages(() => { + sendbirdAction.markAsRead(this.channel); + this.body.scrollToBottom(); + }); + }); + } +} + +export { ChatMain }; diff --git a/javascript/javascript-basic-local-caching/src/js/components/ChatMenu.js b/javascript/javascript-basic-local-caching/src/js/components/ChatMenu.js new file mode 100644 index 00000000..0ad4e845 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/components/ChatMenu.js @@ -0,0 +1,155 @@ +import styles from '../../scss/chat-menu.scss'; +import { appendToFirst, errorAlert, createDivEl } from '../utils'; +import { DISPLAY_FLEX, DISPLAY_NONE } from '../const'; +import { Spinner } from './Spinner'; +import { ChatUserItem } from './ChatUserItem'; +import { SendBirdAction } from '../SendBirdAction'; + +const Type = { + PARTICIPANTS: 'PARTICIPANTS', + MEMBERS: 'MEMBERS', + BLOCKED: 'BLOCKED' +}; + +class ChatMenu { + constructor(channel) { + this.channel = channel; + this.element = createDivEl({ className: styles['chat-menu-root'] }); + this.listElement = null; + this.type = null; + this._createListElement(); + this._createElement(); + } + + _createListElement() { + this.listElement = createDivEl({ className: styles['menu-list'] }); + + const title = createDivEl({ className: styles['list-title'] }); + title.addEventListener('click', () => { + this.type = null; + this.list.innerHTML = ''; + this.listElement.style.display = DISPLAY_NONE; + }); + this.listElement.appendChild(title); + const backBtn = createDivEl({ className: styles['list-back'] }); + title.appendChild(backBtn); + this.titleText = createDivEl({ className: styles['list-text'] }); + title.appendChild(this.titleText); + + this.list = createDivEl({ className: styles['list-body'] }); + this.list.addEventListener('scroll', () => { + if (this.type === Type.BLOCKED) { + this._getBlockedList(this.type); + } + }); + this.listElement.appendChild(this.list); + + this.element.appendChild(this.listElement); + } + + _createElement() { + const usersItem = createDivEl({ className: styles['menu-item'] }); + const users = createDivEl({ + className: styles['menu-users'], + content: Type.MEMBERS + }); + usersItem.appendChild(users); + const arrowUser = createDivEl({ className: styles['menu-arrow'] }); + usersItem.appendChild(arrowUser); + usersItem.addEventListener('click', () => { + this._renderList(users.textContent); + }); + this.element.appendChild(usersItem); + + const blockedItem = createDivEl({ className: styles['menu-item'] }); + const blocked = createDivEl({ className: styles['menu-blocked'], content: Type.BLOCKED }); + blockedItem.appendChild(blocked); + const arrowBlocked = createDivEl({ className: styles['menu-arrow'] }); + blockedItem.appendChild(arrowBlocked); + blockedItem.addEventListener('click', () => { + this._renderList(blocked.textContent); + }); + this.element.appendChild(blockedItem); + } + + _renderList(listTitle) { + switch (listTitle) { + case Type.MEMBERS: + this.type = Type.MEMBERS; + this._getMemberList(listTitle); + break; + case Type.BLOCKED: + this.type = Type.BLOCKED; + this._getBlockedList(listTitle, true); + break; + default: + this.titleText.innerHTML = ''; + break; + } + } + + _getMemberList(listTitle) { + if (this.channel.isGroupChannel()) { + Spinner.start(this.listElement); + this.list.innerHTML = ''; + this.titleText.innerHTML = listTitle; + this.listElement.style.display = DISPLAY_FLEX; + this.channel.members.forEach(user => { + const memberItem = new ChatUserItem({ user, hasEvent: false }); + this.list.appendChild(memberItem.element); + }); + Spinner.remove(); + } + } + + _getBlockedList(listTitle, isInit = false) { + Spinner.start(this.listElement); + if (isInit) { + this.list.innerHTML = ''; + this.titleText.innerHTML = listTitle; + this.listElement.style.display = DISPLAY_FLEX; + } + SendBirdAction.getInstance() + .getBlockedList(isInit) + .then(blockedList => { + blockedList.forEach(user => { + const blockedItem = new ChatUserItem({ user, hasEvent: true }); + this.list.appendChild(blockedItem.element); + }); + Spinner.remove(); + }) + .catch(error => { + errorAlert(error.message); + }); + } + + updateBlockedList(user, isBlock) { + if (this.list) { + if (isBlock) { + const blockedItem = new ChatUserItem({ user, hasEvent: true }); + appendToFirst(this.list, blockedItem.element); + } else { + const items = this.list.childNodes; + for (let i = 0; i < items.length; i++) { + if (items[0].id === user.userId) { + this.list.removeChild(items[0]); + break; + } + } + } + } + } + + updateMenu(channel) { + if (this.type === Type.MEMBERS) { + this.channel = channel; + this._getMemberList(this.type); + } + } + + static get Type() { + return Type; + } +} + +export { ChatMenu }; diff --git a/javascript/javascript-basic-local-caching/src/js/components/ChatTopMenu.js b/javascript/javascript-basic-local-caching/src/js/components/ChatTopMenu.js new file mode 100644 index 00000000..9c81f892 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/components/ChatTopMenu.js @@ -0,0 +1,73 @@ +import styles from '../../scss/chat-top-menu.scss'; +import { createDivEl, errorAlert, protectFromXSS } from '../utils'; +import { Chat } from '../Chat'; +import { UserList } from './UserList'; +import { SendBirdAction } from '../SendBirdAction'; + +class ChatTopMenu { + constructor(channel) { + this.channel = channel; + this.element = this._createElement(channel); + } + + get chatTitle() { + return this.channel.members + .map(member => { + return protectFromXSS(member.nickname); + }) + .join(', '); + } + + _createElement(channel) { + const root = createDivEl({ className: styles['chat-top'] }); + + this.title = createDivEl({ + className: [styles['chat-title'], styles['is-group']], + content: this.chatTitle + }); + root.appendChild(this.title); + + const button = createDivEl({ className: styles['chat-button'] }); + const invite = createDivEl({ className: styles['button-invite'] }); + invite.addEventListener('click', () => { + UserList.getInstance().render(true); + }); + button.appendChild(invite); + const hide = createDivEl({ className: styles['button-hide'] }); + hide.addEventListener('click', () => { + SendBirdAction.getInstance() + .hide(channel.url) + .then(() => { + // ChatLeftMenu.getInstance().removeGroupChannelItem(this.channel.url); + Chat.getInstance().renderEmptyElement(); + }) + .catch(error => { + errorAlert(error.message); + }); + }); + button.appendChild(hide); + + const leave = createDivEl({ className: styles['button-leave'] }); + leave.addEventListener('click', () => { + SendBirdAction.getInstance() + .leave(channel.url) + .then(() => { + // ChatLeftMenu.getInstance().removeGroupChannelItem(this.channel.url); + Chat.getInstance().renderEmptyElement(); + }) + .catch(error => { + errorAlert(error.message); + }); + }); + button.appendChild(leave); + root.appendChild(button); + return root; + } + + updateTitle(channel) { + this.channel = channel; + this.title.innerHTML = this.chatTitle; + } +} + +export { ChatTopMenu }; diff --git a/javascript/javascript-basic-local-caching/src/js/components/ChatUserItem.js b/javascript/javascript-basic-local-caching/src/js/components/ChatUserItem.js new file mode 100644 index 00000000..fcc51d66 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/components/ChatUserItem.js @@ -0,0 +1,49 @@ +import styles from '../../scss/chat-user-item.scss'; +import { createDivEl, protectFromXSS } from '../utils'; +import { COLOR_RED } from '../const'; +import { UserBlockModal } from './UserBlockModal'; +import { SendBirdAction } from '../SendBirdAction'; + +class ChatUserItem { + constructor({ user, hasEvent }) { + this.user = user; + this.hasEvent = hasEvent; + this.element = null; + this._create(); + } + + _create() { + this.element = createDivEl({ className: styles['chat-user-item'], id: this.user.userId }); + if (this.hasEvent) { + this.element.addEventListener('mouseover', () => { + this._hoverOnUser(this.user.nickname, true); + }); + this.element.addEventListener('mouseleave', () => { + this._hoverOnUser(this.user.nickname, false); + }); + this.element.addEventListener('click', () => { + const userBlockModal = new UserBlockModal({ user: this.user, isBlock: false }); + userBlockModal.render(); + }); + } + + const image = createDivEl({ className: styles['user-image'], background: protectFromXSS(this.user.profileUrl) }); + this.element.appendChild(image); + + this.nickname = createDivEl({ + className: SendBirdAction.getInstance().isCurrentUser(this.user) + ? [styles['user-nickname'], styles['is-user']] + : styles['user-nickname'], + content: protectFromXSS(this.user.nickname) + }); + this.element.appendChild(this.nickname); + } + + _hoverOnUser(nickname, hover) { + this.nickname.innerHTML = hover ? 'UNBLOCK' : protectFromXSS(nickname); + this.nickname.style.color = hover ? COLOR_RED : ''; + this.nickname.style.opacity = hover ? '1' : ''; + } +} + +export { ChatUserItem }; diff --git a/javascript/javascript-basic-local-caching/src/js/components/LeftListItem.js b/javascript/javascript-basic-local-caching/src/js/components/LeftListItem.js new file mode 100644 index 00000000..43d3dbb4 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/components/LeftListItem.js @@ -0,0 +1,138 @@ +import styles from '../../scss/list-item.scss'; +import { + addClass, + createDivEl, + getDataInElement, + protectFromXSS, + removeClass, + setDataInElement, + timestampFromNow +} from '../utils'; +import { ChatLeftMenu } from '../ChatLeftMenu'; + +const KEY_MESSAGE_LAST_TIME = 'origin'; + +class LeftListItem { + constructor({ channel, handler }) { + this.channel = channel; + this.element = this._createElement(handler); + } + + get channelUrl() { + return this.channel.url; + } + + get title() { + return this.channel.members + .map(member => { + return protectFromXSS(member.nickname); + }) + .join(', '); + } + + get lastMessagetime() { + if (!this.channel.lastMessage) { + return 0; + } else { + return this.channel.lastMessage.createdAt; + } + } + + get lastMessageTimeText() { + if (!this.channel.lastMessage) { + return 0; + } else { + return LeftListItem.getTimeFromNow(this.channel.lastMessage.createdAt); + } + } + + get lastMessageText() { + if (!this.channel.lastMessage) { + return ''; + } else { + return this.channel.lastMessage.isFileMessage() + ? protectFromXSS(this.channel.lastMessage.name) + : protectFromXSS(this.channel.lastMessage.message); + } + } + + get memberCount() { + return this.channel.memberCount; + } + + get unreadMessageCount() { + const count = this.channel.unreadMessageCount > 9 ? '+9' : this.channel.unreadMessageCount.toString(); + return count; + } + + _createElement(handler) { + const item = createDivEl({ className: styles['list-item'], id: this.channelUrl }); + const itemTop = createDivEl({ className: styles['item-top'] }); + const itemTopCount = createDivEl({ className: styles['item-count'], content: this.memberCount }); + const itemTopTitle = createDivEl({ className: styles['item-title'], content: this.title }); + itemTop.appendChild(itemTopCount); + itemTop.appendChild(itemTopTitle); + item.appendChild(itemTop); + + const itemBottom = createDivEl({ className: styles['item-bottom'] }); + + const itemBottomMessage = createDivEl({ className: styles['item-message'] }); + const itemBottomMessageText = createDivEl({ + className: styles['item-message-text'], + content: this.lastMessageText + }); + itemBottomMessage.appendChild(itemBottomMessageText); + const itemBottomMessageUnread = createDivEl({ + className: [styles['item-message-unread'], styles.active], + content: this.unreadMessageCount + }); + itemBottomMessage.appendChild(itemBottomMessageUnread); + + const itemBottomTime = createDivEl({ className: styles['item-time'], content: this.lastMessageTimeText }); + setDataInElement(itemBottomTime, KEY_MESSAGE_LAST_TIME, this.lastMessagetime); + itemBottom.appendChild(itemBottomMessage); + itemBottom.appendChild(itemBottomTime); + item.appendChild(itemBottom); + + item.addEventListener('click', () => { + if (handler) handler(); + }); + return item; + } + + static updateUnreadCount() { + const items = ChatLeftMenu.getInstance().groupChannelList.getElementsByClassName(styles['item-message-unread']); + if (items && items.length > 0) { + Array.prototype.slice.call(items).forEach(targetItemEl => { + const originTs = targetItemEl.textContent; + if (originTs === '0') { + removeClass(targetItemEl, styles.active); + } else { + addClass(targetItemEl, styles.active); + } + }); + } + } + + static updateLastMessageTime() { + const items = ChatLeftMenu.getInstance().groupChannelList.getElementsByClassName(styles['item-time']); + if (items && items.length > 0) { + Array.prototype.slice.call(items).forEach(targetItemEl => { + const originTs = parseInt(getDataInElement(targetItemEl, KEY_MESSAGE_LAST_TIME)); + if (originTs) { + targetItemEl.innerHTML = LeftListItem.getTimeFromNow(originTs); + } + }); + } + } + + static getTimeFromNow(timestamp) { + return timestampFromNow(timestamp); + } + + static getItemRootClassName() { + return styles['list-item']; + } +} + +export { LeftListItem }; diff --git a/javascript/javascript-basic-local-caching/src/js/components/List.js b/javascript/javascript-basic-local-caching/src/js/components/List.js new file mode 100644 index 00000000..2350f8ec --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/components/List.js @@ -0,0 +1,80 @@ +import styles from '../../scss/list.scss'; +import { createDivEl, isScrollBottom } from '../utils'; + +let instance = null; + +class List { + constructor(title, createSearchBox = false) { + if (instance) { + return instance; + } + this.createSearchBox = createSearchBox; + this.element = this._create(title); + this.scrollEventHandler = null; + this.closeEventHandler = null; + this.searchKeyword = ''; + } + + _create(title) { + const root = createDivEl({ className: styles['list-root'] }); + + const listBody = createDivEl({ className: styles['list-body'] }); + root.appendChild(listBody); + + const listTop = createDivEl({ className: styles['list-top'] }); + listBody.appendChild(listTop); + + const listTopTitle = createDivEl({ className: styles['list-title'], content: title }); + listTop.appendChild(listTopTitle); + const listTopButton = createDivEl({ className: styles['list-button'] }); + listTop.appendChild(listTopButton); + const listTopButtonExit = createDivEl({ className: styles['button-exit'] }); + listTopButton.appendChild(listTopButtonExit); + listTopButtonExit.addEventListener('click', () => { + this.searchKeyword = ''; + const listContent = document.querySelector(`.${styles['list-content']}`); + if (this.closeEventHandler) { + this.closeEventHandler(); + } + listContent.innerHTML = ''; + root.parentElement.removeChild(this.element); + }); + this.buttonRootElement = listTopButton; + + const hr = createDivEl({ className: styles['list-hr'] }); + listBody.appendChild(hr); + + const listContent = createDivEl({ className: styles['list-content'] }); + listBody.appendChild(listContent); + listContent.addEventListener('scroll', () => { + if (isScrollBottom(listContent)) { + if (this.scrollEventHandler) { + this.scrollEventHandler(false, this.searchKeyword); + } + } + }); + + return root; + } + + close() { + const btnExit = document.querySelector(`.${styles['button-exit']}`); + if (btnExit) { + document.querySelector(`.${styles['button-exit']}`).click(); + } + } + + getRootElement() { + return document.querySelector(`.${styles['list-root']}`); + } + + getRootClassName() { + return styles['list-root']; + } + + getContentElement() { + return document.querySelector(`.${styles['list-content']}`); + } +} + +export { List }; diff --git a/javascript/javascript-basic-local-caching/src/js/components/Message.js b/javascript/javascript-basic-local-caching/src/js/components/Message.js new file mode 100644 index 00000000..ec32cd31 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/components/Message.js @@ -0,0 +1,249 @@ +import styles from '../../scss/message.scss'; +import { createDivEl, isImage, protectFromXSS, setDataInElement, timestampToTime } from '../utils'; +import { SendBirdAction } from '../SendBirdAction'; +import { COLOR_RED, MESSAGE_REQ_ID } from '../const'; +import { MessageDeleteModal } from './MessageDeleteModal'; +import { UserBlockModal } from './UserBlockModal'; +import { Chat } from '../Chat'; + +class Message { + constructor({ channel, message, isManual = false, col = null }) { + this.channel = channel; + this.message = message; + this.isPending = message.messageId === 0 && message.sendingStatus === 'pending'; + this.isFailed = message.messageId === 0 && message.sendingStatus === 'failed'; + this.isManual = (this.isPending || this.isFailed) ? isManual : false; + this.element = this._createElement(); + if (col) { + this.col = col; + } + } + + _createElement() { + if (this.message.isUserMessage()) { + return this._createUserElement(); + } else if (this.message.isFileMessage()) { + return this._createFileElement(); + } else if (this.message.isAdminMessage()) { + return this._createAdminElement(); + } else { + // console.error('Message is invalid data.'); + return null; + } + } + + _hoverOnNickname(nickname, hover) { + if (!SendBirdAction.getInstance().isCurrentUser(this.message.sender)) { + nickname.innerHTML = hover ? 'BLOCK ' : `${protectFromXSS(this.message.sender.nickname)} : `; + nickname.style.color = hover ? COLOR_RED : ''; + nickname.style.opacity = hover ? '1' : ''; + } + } + + _hoverOnTime(time, hover) { + if (SendBirdAction.getInstance().isCurrentUser(this.message.sender)) { + time.innerHTML = hover ? 'DELETE' : timestampToTime(this.message.createdAt); + time.style.color = hover ? COLOR_RED : ''; + time.style.opacity = hover ? '1' : ''; + time.style.fontWeight = hover ? '600' : ''; + } + } + + _createUserElement() { + const sendbirdAction = SendBirdAction.getInstance(); + const isCurrentUser = sendbirdAction.isCurrentUser(this.message.sender); + let root; + if (this.isFailed && !this.isManual) { + root = createDivEl({ + className: [styles['chat-message'], styles['is-failed']], + id: this.message.reqId + }); + } else if (this.isPending && !this.isManual) { + root = createDivEl({ + className: [styles['chat-message'], styles['is-pending']], + id: this.message.reqId + }); + } else { + root = createDivEl({ + className: styles['chat-message'], + id: this.message.reqId + }); + } + setDataInElement(root, MESSAGE_REQ_ID, this.message.reqId); + + const messageContent = createDivEl({ className: styles['message-content'] }); + const nickname = createDivEl({ + className: isCurrentUser ? [styles['message-nickname'], styles['is-user']] : styles['message-nickname'], + content: `${protectFromXSS(this.message.sender.nickname)} : ` + }); + nickname.addEventListener('mouseover', () => { + this._hoverOnNickname(nickname, true); + }); + nickname.addEventListener('mouseleave', () => { + this._hoverOnNickname(nickname, false); + }); + nickname.addEventListener('click', () => { + if (!isCurrentUser) { + const userBlockModal = new UserBlockModal({ user: this.message.sender, isBlock: true }); + userBlockModal.render(); + } + }); + messageContent.appendChild(nickname); + + const msg = createDivEl({ className: styles['message-content'], content: protectFromXSS(this.message.message) }); + messageContent.appendChild(msg); + + if (this.isFailed && this.isManual) { + const resendButton = createDivEl({ + className: styles['resend-button'], + content: 'RESEND' + }); + resendButton.addEventListener('click', () => { + this._resendUserMessage(); + }); + messageContent.appendChild(resendButton); + } + if (this.isFailed) { + const deleteButton = createDivEl({ + className: styles['delete-button'], + content: 'DELETE' + }); + deleteButton.addEventListener('click', () => { + if (isCurrentUser) { + const messageDeleteModal = new MessageDeleteModal({ + channel: this.channel, + message: this.message, + col: this.col + }); + messageDeleteModal.render(); + } + }); + messageContent.appendChild(deleteButton); + } + if (!this.isFailed) { + const time = createDivEl({ + className: isCurrentUser ? [styles.time, styles['is-user']] : styles.time, + content: timestampToTime(this.message.createdAt) + }); + time.addEventListener('mouseover', () => { + this._hoverOnTime(time, true); + }); + time.addEventListener('mouseleave', () => { + this._hoverOnTime(time, false); + }); + time.addEventListener('click', () => { + if (isCurrentUser) { + const messageDeleteModal = new MessageDeleteModal({ + channel: this.channel, + message: this.message + }); + messageDeleteModal.render(); + } + }); + messageContent.appendChild(time); + + const count = sendbirdAction.getReadReceipt(this.channel, this.message); + const read = createDivEl({ + className: count ? [styles.read, styles.active] : styles.read, + content: count + }); + messageContent.appendChild(read); + } + + root.appendChild(messageContent); + return root; + } + + _resendUserMessage() { + this.channel.resendUserMessage(this.message, (error, message) => { }); + } + + _createFileElement() { + const sendbirdAction = SendBirdAction.getInstance(); + const root = createDivEl({ className: styles['chat-message'], id: this.message.messageId }); + setDataInElement(root, MESSAGE_REQ_ID, this.message.reqId); + + const messageContent = createDivEl({ className: styles['message-content'] }); + const nickname = createDivEl({ + className: sendbirdAction.isCurrentUser(this.message.sender) + ? [styles['message-nickname'], styles['is-user']] + : styles['message-nickname'], + content: `${protectFromXSS(this.message.sender.nickname)} : ` + }); + messageContent.appendChild(nickname); + + const msg = createDivEl({ + className: [styles['message-content'], styles['is-file']], + content: protectFromXSS(this.message.name) + }); + msg.addEventListener('click', () => { + window.open(this.message.url); + }); + messageContent.appendChild(msg); + + const time = createDivEl({ className: styles.time, content: timestampToTime(this.message.createdAt) }); + time.addEventListener('mouseover', () => { + this._hoverOnTime(time, true); + }); + time.addEventListener('mouseleave', () => { + this._hoverOnTime(time, false); + }); + time.addEventListener('click', () => { + const messageDeleteModal = new MessageDeleteModal({ + channel: this.channel, + message: this.message + }); + messageDeleteModal.render(); + }); + messageContent.appendChild(time); + + if (this.channel.isGroupChannel()) { + const count = sendbirdAction.getReadReceipt(this.channel, this.message); + const read = createDivEl({ + className: count ? [styles.read, styles.active] : styles.read, + content: count + }); + messageContent.appendChild(read); + } + + root.appendChild(messageContent); + + if (this.message.isFileMessage() && this.message.messageId) { + const fileContent = createDivEl({ className: styles['file-content'] }); + fileContent.addEventListener('click', () => { + window.open(this.message.url); + }); + if (this.message.thumbnails.length > 0 || isImage(this.message.type)) { + const fileRender = document.createElement('img'); + fileRender.className = styles['file-render']; + + if (isImage(this.message.type)) { + fileRender.src = protectFromXSS(this.message.url); + } else if (this.message.thumbnails.length > 0) { + fileRender.src = protectFromXSS(this.message.thumbnails[0].url); + } + + fileRender.onload = () => { + Chat.getInstance().main.repositionScroll(fileRender.offsetHeight); + }; + fileContent.appendChild(fileRender); + } + root.appendChild(fileContent); + } + + return root; + } + + _createAdminElement() { + const root = createDivEl({ className: styles['chat-message'], id: this.message.messageId }); + const msg = createDivEl({ className: styles['message-admin'], content: protectFromXSS(this.message.message) }); + root.appendChild(msg); + return root; + } + + static getReadReceiptElementClassName() { + return styles.active; + } +} + +export { Message }; diff --git a/javascript/javascript-basic-local-caching/src/js/components/MessageDeleteModal.js b/javascript/javascript-basic-local-caching/src/js/components/MessageDeleteModal.js new file mode 100644 index 00000000..ffa1e6ab --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/components/MessageDeleteModal.js @@ -0,0 +1,42 @@ +import styles from '../../scss/message-delete-modal.scss'; +import { createDivEl, errorAlert, protectFromXSS } from '../utils'; +import { SendBirdAction } from '../SendBirdAction'; +import { Spinner } from './Spinner'; +import { Modal } from './Modal'; + +const title = 'Delete Message'; +const description = 'Are you Sure? Do you want to delete message?'; +const submitText = 'DELETE'; + +class MessageDeleteModal extends Modal { + constructor({ channel, message, col }) { + super({ title, description, submitText }); + this.channel = channel; + this.message = message; + this.col = col; + this._createElement(); + + this.submitHandler = () => { + SendBirdAction.getInstance() + .deleteMessage({ channel: this.channel, message: this.message, col: this.col }) + .then(() => { + Spinner.remove(); + this.close(); + }) + .catch(error => { + Spinner.remove(); + errorAlert(error.message); + }); + }; + } + + _createElement() { + const content = createDivEl({ + className: styles['modal-message'], + content: this.message.isFileMessage() ? protectFromXSS(this.message.name) : protectFromXSS(this.message.message) + }); + this.contentElement.appendChild(content); + } +} + +export { MessageDeleteModal }; diff --git a/javascript/javascript-basic-local-caching/src/js/components/Modal.js b/javascript/javascript-basic-local-caching/src/js/components/Modal.js new file mode 100644 index 00000000..d90ea634 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/components/Modal.js @@ -0,0 +1,62 @@ +import styles from '../../scss/modal.scss'; +import { createDivEl } from '../utils'; +import { Spinner } from './Spinner'; + +class Modal { + constructor({ title, description, submitText }) { + this.contentElement = null; + this.cancelHandler = null; + this.submitHandler = null; + this.element = this._create({ title, description, submitText }); + } + + _create({ title, description, submitText }) { + const root = createDivEl({ className: styles['modal-root'] }); + const modal = createDivEl({ className: styles['modal-body'] }); + root.appendChild(modal); + + const titleText = createDivEl({ className: styles['modal-title'], content: title }); + modal.appendChild(titleText); + + const desc = createDivEl({ className: styles['modal-desc'], content: description }); + modal.appendChild(desc); + + this.contentElement = createDivEl({ className: styles['modal-content'] }); + modal.appendChild(this.contentElement); + + const bottom = createDivEl({ className: styles['modal-bottom'] }); + modal.appendChild(bottom); + const cancel = createDivEl({ className: styles['modal-cancel'], content: 'CANCEL' }); + cancel.addEventListener('click', () => { + if (this.cancelHandler) { + this.cancelHandler(); + } + this.close(); + }); + bottom.appendChild(cancel); + const submit = createDivEl({ className: styles['modal-submit'], content: submitText }); + submit.addEventListener('click', () => { + Spinner.start(modal); + if (this.submitHandler) { + this.submitHandler(); + } + }); + bottom.appendChild(submit); + + return root; + } + + close() { + if (document.body.contains(this.element)) { + document.body.removeChild(this.element); + } + } + + render() { + if (!document.body.querySelector(`.${styles['modal-root']}`)) { + document.body.appendChild(this.element); + } + } +} + +export { Modal }; diff --git a/javascript/javascript-basic-local-caching/src/js/components/Spinner.js b/javascript/javascript-basic-local-caching/src/js/components/Spinner.js new file mode 100644 index 00000000..b7d83297 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/components/Spinner.js @@ -0,0 +1,42 @@ +import styles from '../../scss/spinner.scss'; +import { createDivEl } from '../utils'; + +let instance = null; + +class Spinner { + constructor() { + if (instance) { + return instance; + } + this.element = this._createSpinner(); + instance = this; + } + + _createSpinner() { + const item = createDivEl({ className: styles['sb-spinner'] }); + const bubble = createDivEl({ className: styles['sb-spinner-bubble'] }); + item.appendChild(bubble); + return item; + } + + static start(target) { + const spinnerEl = Spinner.getInstance().element; + if (!target.contains(spinnerEl)) { + target.appendChild(spinnerEl); + } + } + + static remove() { + const spinnerEl = Spinner.getInstance().element; + const targetEl = spinnerEl.parentElement; + if (targetEl && targetEl.contains(spinnerEl)) { + spinnerEl.parentElement.removeChild(spinnerEl); + } + } + + static getInstance() { + return new Spinner(); + } +} + +export { Spinner }; diff --git a/javascript/javascript-basic-local-caching/src/js/components/Toast.js b/javascript/javascript-basic-local-caching/src/js/components/Toast.js new file mode 100644 index 00000000..c215c251 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/components/Toast.js @@ -0,0 +1,49 @@ +import styles from '../../scss/toast.scss'; +import { createDivEl } from '../utils'; + +let instance = null; + +class Toast { + constructor(message) { + if (instance) { + const messageEl = instance.element.getElementsByClassName('sb-toast-message')[0]; + if (messageEl) { + if (!message) { + message = messageEl.innerHTML; + } + messageEl.innerHTML = message; + } + return instance; + } + this.element = this._createToast(message); + instance = this; + } + + _createToast(text) { + const item = createDivEl({ className: styles['sb-toast'] }); + const message = createDivEl({ className: styles['sb-toast-message'] }); + message.innerHTML = text; + item.appendChild(message); + return item; + } + + static start(target, message) { + const toast = new Toast(message); + const toastEl = toast.element; + if (!target.contains(toastEl)) { + target.appendChild(toastEl); + } + } + + static remove() { + const toastEl = instance ? instance.element : null; + if (toastEl) { + const targetEl = toastEl.parentElement; + if (targetEl && targetEl.contains(toastEl)) { + toastEl.parentElement.removeChild(toastEl); + } + } + } +} + +export { Toast }; diff --git a/javascript/javascript-basic-local-caching/src/js/components/UserBlockModal.js b/javascript/javascript-basic-local-caching/src/js/components/UserBlockModal.js new file mode 100644 index 00000000..85f9d1c7 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/components/UserBlockModal.js @@ -0,0 +1,53 @@ +import styles from '../../scss/user-block-modal.scss'; +import { createDivEl, errorAlert, protectFromXSS } from '../utils'; +import { SendBirdAction } from '../SendBirdAction'; +import { Spinner } from './Spinner'; +import { Modal } from './Modal'; +import { Chat } from '../Chat'; + +const blockTitle = 'Block User'; +const blockDescription = 'Are you Sure? Do you want to block this user?'; +const blockSubmitText = 'BLOCK'; + +const unblockTitle = 'Unblock User'; +const unblockDescription = 'Are you Sure? Do you want to unblock this user?'; +const unblockSubmitText = 'UNBLOCK'; + +class UserBlockModal extends Modal { + constructor({ user, isBlock = true }) { + isBlock + ? super({ title: blockTitle, description: blockDescription, submitText: blockSubmitText }) + : super({ title: unblockTitle, description: unblockDescription, submitText: unblockSubmitText }); + this.isBlock = isBlock; + this.user = user; + this._createElement(); + + this.submitHandler = () => { + SendBirdAction.getInstance() + .blockUser(this.user, this.isBlock) + .then(() => { + Chat.getInstance().main.updateBlockedList(this.user, this.isBlock); + Spinner.remove(); + this.close(); + }) + .catch(error => { + Spinner.remove(); + errorAlert(error.message); + }); + }; + } + + _createElement() { + const content = createDivEl({ className: styles['modal-user'] }); + + const image = createDivEl({ className: styles['user-profile'], background: protectFromXSS(this.user.profileUrl) }); + content.appendChild(image); + + const nickname = createDivEl({ className: styles['user-nickname'], content: protectFromXSS(this.user.nickname) }); + content.appendChild(nickname); + + this.contentElement.appendChild(content); + } +} + +export { UserBlockModal }; diff --git a/javascript/javascript-basic-local-caching/src/js/components/UserItem.js b/javascript/javascript-basic-local-caching/src/js/components/UserItem.js new file mode 100644 index 00000000..799ec0cb --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/components/UserItem.js @@ -0,0 +1,63 @@ +import styles from '../../scss/user-item.scss'; +import { createDivEl, protectFromXSS, timestampFromNow, toggleClass } from '../utils'; + +class UserItem { + constructor({ user, handler }) { + this.user = user; + this.element = this._createElement(handler); + } + + get userId() { + return this.user.userId; + } + + get nickname() { + return protectFromXSS(this.user.nickname); + } + + get profileUrl() { + return protectFromXSS(this.user.profileUrl); + } + + get lastSeenTimeString() { + return this.user.lastSeenAt ? timestampFromNow(this.user.lastSeenAt) : ''; + } + + get isOnline() { + return this.user.connectionStatus === 'online'; + } + + _createElement(handler) { + const item = createDivEl({ className: styles['user-item'], id: this.userId }); + + const userInfo = createDivEl({ className: styles['user-info'] }); + item.appendChild(userInfo); + const profile = createDivEl({ className: styles['user-profile'], background: this.profileUrl }); + userInfo.appendChild(profile); + const nickname = createDivEl({ className: styles['user-nickname'], content: this.nickname }); + userInfo.appendChild(nickname); + const isOnline = createDivEl({ + className: this.isOnline ? [styles['user-online'], styles.active] : styles['user-online'] + }); + userInfo.appendChild(isOnline); + + const userState = createDivEl({ className: styles['user-state'] }); + item.appendChild(userState); + const lastSeenTime = createDivEl({ className: styles['user-time'], content: this.lastSeenTimeString }); + userState.appendChild(lastSeenTime); + const selectIcon = createDivEl({ className: styles['user-select'] }); + userState.appendChild(selectIcon); + item.addEventListener('click', () => { + toggleClass(item.querySelector(`.${UserItem.selectIconClassName}`), styles.active); + if (handler) handler(); + }); + + return item; + } + + static get selectIconClassName() { + return styles['user-select']; + } +} + +export { UserItem }; diff --git a/javascript/javascript-basic-local-caching/src/js/components/UserList.js b/javascript/javascript-basic-local-caching/src/js/components/UserList.js new file mode 100644 index 00000000..a93c9837 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/components/UserList.js @@ -0,0 +1,128 @@ +import styles from '../../scss/user-list.scss'; +import { createDivEl, errorAlert, appendToFirst } from '../utils'; +import { List } from './List'; +import { Spinner } from './Spinner'; +import { SendBirdAction } from '../SendBirdAction'; +import { UserItem } from './UserItem'; +import { Chat } from '../Chat'; +import { ChatLeftMenu } from '../ChatLeftMenu'; + +let instance = null; + +class UserList extends List { + constructor() { + super('User List'); + if (instance) { + return instance; + } + + this.scrollEventHandler = this._getUserList; + this.closeEventHandler = this._close; + this.createBtn = this._addCreateBtn(); + this.selectedUserIds = []; + instance = this; + } + + _addCreateBtn() { + const createBtn = createDivEl({ className: styles['button-create'], content: 'CREATE' }); + const oldCreateBtn = this.buttonRootElement.getElementsByClassName(styles['button-create'])[0]; + if (oldCreateBtn) { + this.buttonRootElement.removeChild(oldCreateBtn); + } + appendToFirst(this.buttonRootElement, createBtn); + return createBtn; + } + + _createChannel() { + SendBirdAction.getInstance() + .createGroupChannel(this.selectedUserIds) + .then(channel => { + ChatLeftMenu.getInstance().activeChannelUrl = channel.url; + Chat.getInstance().render(channel, false); + Spinner.remove(); + this.close(); + }) + .catch(error => { + Spinner.remove(); + errorAlert(error.message); + }); + } + + _inviteChannel() { + const channelUrl = Chat.getInstance().channel.url; + SendBirdAction.getInstance() + .inviteGroupChannel(channelUrl, this.selectedUserIds) + .then(() => { + Spinner.remove(); + this.close(); + }) + .catch(error => { + Spinner.remove(); + errorAlert(error.message); + }); + } + + _updateCreateType(isInvite) { + this.createBtn = this._addCreateBtn(); + this.createBtn.innerHTML = isInvite ? 'INVITE' : 'CREATE'; + this.createBtn.addEventListener('click', () => { + Spinner.start(this.element); + if (isInvite) { + this._inviteChannel(); + } else { + this._createChannel(); + } + }); + } + + _getUserList(isInit = false) { + Spinner.start(this.element); + const sendbirdAction = SendBirdAction.getInstance(); + const listContent = this.getContentElement(); + sendbirdAction + .getUserList(isInit) + .then(userList => { + userList.forEach(user => { + if (!sendbirdAction.isCurrentUser(user)) { + const handler = () => { + this._toggleUserId(item.userId); + }; + const item = new UserItem({ user, handler }); + listContent.appendChild(item.element); + } + }); + Spinner.remove(); + }) + .catch(error => { + Spinner.remove(); + errorAlert(error.message); + }); + } + + _toggleUserId(userId) { + const index = this.selectedUserIds.indexOf(userId); + if (index > -1) { + this.selectedUserIds.splice(index, 1); + } else { + this.selectedUserIds.push(userId); + } + } + + _close() { + this.selectedUserIds = []; + } + + render(isInvite = false) { + if (!document.body.querySelector(`.${this.getRootClassName()}`)) { + this._updateCreateType(isInvite); + document.body.appendChild(this.element); + this._getUserList(true); + } + } + + static getInstance() { + return new UserList(); + } +} + +export { UserList }; diff --git a/javascript/javascript-basic-local-caching/src/js/const.js b/javascript/javascript-basic-local-caching/src/js/const.js new file mode 100644 index 00000000..f4d5f183 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/const.js @@ -0,0 +1,11 @@ +export const APP_ID = '9DA1B1F4-0BE6-4DA8-82C5-2E81DAB56F23'; +export const USER_ID = 'user_id'; +export const DISPLAY_NONE = 'none'; +export const DISPLAY_BLOCK = 'block'; +export const DISPLAY_FLEX = 'flex'; +export const ACTIVE_CLASSNAME = 'active'; +export const KEY_ENTER = 13; +export const FILE_ID = 'attach_file_id'; +export const UPDATE_INTERVAL_TIME = 5 * 1000; +export const COLOR_RED = '#DC5960'; +export const MESSAGE_REQ_ID = 'reqId'; diff --git a/javascript/javascript-basic-local-caching/src/js/index.js b/javascript/javascript-basic-local-caching/src/js/index.js new file mode 100644 index 00000000..5cbeefcf --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/index.js @@ -0,0 +1,36 @@ +import { isEmpty, setCookie, getCookie } from './utils'; +import { USER_ID, KEY_ENTER } from './const'; + +const userIdEl = document.querySelector('#user_id'); +const nicknameEl = document.querySelector('#user_nickname'); +const buttonEl = document.querySelector('#login-button'); + +document.addEventListener('DOMContentLoaded', () => { + const cookieUserId = getCookie(USER_ID); + if (cookieUserId) { + userIdEl.value = cookieUserId; + } +}); + +nicknameEl.addEventListener('keydown', e => { + if (e.which === KEY_ENTER) { + login(); + } +}); + +buttonEl.addEventListener('click', () => { + login(); +}); + +const login = () => { + const userId = userIdEl.value.trim(); + const nickname = nicknameEl.value.trim(); + if (isEmpty(nickname)) { + alert('Please enter user nickname'); + return; + } + userIdEl.value = ''; + nicknameEl.value = ''; + setCookie(USER_ID, userId); + window.location.href = `chat.html?userid=${encodeURIComponent(userId)}&nickname=${encodeURIComponent(nickname)}`; +}; diff --git a/javascript/javascript-basic-local-caching/src/js/main.js b/javascript/javascript-basic-local-caching/src/js/main.js new file mode 100644 index 00000000..d75ea5ad --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/main.js @@ -0,0 +1,55 @@ +import { getVariableFromUrl, isEmpty, redirectToIndex } from './utils'; +import { SendBirdAction } from './SendBirdAction'; +import { SendBirdConnection } from './SendBirdConnection'; +import { ChatLeftMenu } from './ChatLeftMenu'; +import { Chat } from './Chat'; +import { UPDATE_INTERVAL_TIME } from './const'; +import { LeftListItem } from './components/LeftListItem'; + +import { Toast } from './components/Toast'; + +const sb = new SendBirdAction(); + +let chat = null; +let chatLeft = null; + +const createConnectionHandler = () => { + const connectionManager = new SendBirdConnection(); + connectionManager.onReconnectStarted = () => { + Toast.start(document.body, 'Connection is lost. Trying to reconnect...'); + connectionManager.channel = chat.channel; + }; + connectionManager.onReconnectSucceeded = () => { + chatLeft.updateUserInfo(SendBirdAction.getInstance().getCurrentUser()); + Toast.remove(); + }; + connectionManager.onReconnectFailed = () => { + connectionManager.reconnect(); + }; +}; + +const updateGroupChannelTime = () => { + setInterval(() => { + LeftListItem.updateLastMessageTime(); + }, UPDATE_INTERVAL_TIME); +}; + +document.addEventListener('DOMContentLoaded', () => { + const { userid, nickname } = getVariableFromUrl(); + if (isEmpty(userid) || isEmpty(nickname)) { + redirectToIndex('UserID and Nickname must be required.'); + } + + sb.connect(userid, nickname) + .then(user => { + chat = new Chat(); + chatLeft = new ChatLeftMenu(); + chatLeft.updateUserInfo(user); + updateGroupChannelTime(); + chatLeft.loadGroupChannelList(true); + createConnectionHandler(); + }) + .catch(() => { + Toast.start(document.body, 'Connection is not established.'); + }); +}); diff --git a/javascript/javascript-basic-local-caching/src/js/utils.js b/javascript/javascript-basic-local-caching/src/js/utils.js new file mode 100644 index 00000000..3e94efc2 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/js/utils.js @@ -0,0 +1,231 @@ +import moment from 'moment'; + +export function findChannelIndex(newChannel, channels) { + const newChannelLastMessageUpdated = newChannel.lastMessage ? newChannel.lastMessage.createdAt : newChannel.createdAt; + + let index = channels.length; + for (let i = 0; i < channels.length; i++) { + const comparedChannel = channels[i]; + const comparedChannelLastMessageUpdated = comparedChannel.lastMessage + ? comparedChannel.lastMessage.createdAt + : comparedChannel.createdAt; + if (newChannel.url === comparedChannel.url) { + index = i; + break; + } else if (newChannelLastMessageUpdated > comparedChannelLastMessageUpdated) { + index = i; + break; + } + } + return index; +} +export function findMessageIndex(newMessage, messages, isRequestId = false) { + let index = messages.length; + for (let i = 0; i < messages.length; i++) { + if ( + !isRequestId && + newMessage.messageId !== 0 && + messages[i].messageId !== 0 && + messages[i].messageId === newMessage.messageId + ) { + index = i; + break; + } else if (isRequestId && messages[i].reqId === newMessage.reqId) { + index = i; + break; + } else if (messages[i].createdAt >= newMessage.createdAt) { + index = i; + break; + } + } + return index; +} + +export function mergeFailedWithSuccessful(failedMessages, successfulMessages) { + const wholeMessages = [...successfulMessages]; + for (let i = 0; i < failedMessages.length; i++) { + const index = findMessageIndex(failedMessages[i], wholeMessages); + wholeMessages.splice(index, 0, failedMessages[i]); + } + return wholeMessages; +} + +export const timestampToTime = timestamp => { + const now = new Date().getTime(); + const nowDate = moment.unix(now.toString().length === 13 ? now / 1000 : now).format('MM/DD'); + + let date = moment.unix(timestamp.toString().length === 13 ? timestamp / 1000 : timestamp).format('MM/DD'); + if (date === 'Invalid date') { + date = ''; + } + + return nowDate === date + ? moment.unix(timestamp.toString().length === 13 ? timestamp / 1000 : timestamp).format('HH:mm') + : date; +}; + +export const timestampToDateString = timestamp => { + return moment.unix(timestamp.toString().length === 13 ? timestamp / 1000 : timestamp).format('LL'); +}; + +export const timestampFromNow = timestamp => { + return moment(timestamp).fromNow(); +}; + +export const isUrl = urlString => { + const regex = /^(http|https):\/\/[^ "]+$/; + return regex.test(urlString); +}; + +export const isImage = fileType => { + const regex = /^image\/.+$/; + return regex.test(fileType); +}; + +export const isEmpty = value => { + return value === null || value === undefined || value.length === 0; +}; + +export const isNull = value => { + try { + return value === null; + } catch (e) { + return false; + } +}; + +export const setCookie = (key, value) => { + document.cookie = `${key}=${value}; expires=Fri, 31 Dec 9999 23:59:59 GMT`; +}; + +export const getCookie = key => { + let name = `${key}=`; + let ca = document.cookie.split(';'); + for (let i = 0; i < ca.length; i++) { + let c = ca[i]; + if (!c) continue; + while (c.charAt(0) === ' ') { + c = c.substring(1); + } + if (c.indexOf(name) === 0) { + return c.substring(name.length, c.length); + } + } + return ''; +}; + +export const getVariableFromUrl = () => { + let vars = {}; + let hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); + for (let i = 0; i < hashes.length; i++) { + let hash = hashes[i].split('='); + vars[hash[0]] = hash[1]; + } + return vars; +}; + +export const errorAlert = (message, reload = false) => { + // alert(message); + // eslint-disable-next-line no-console + console.error(message); + if (reload) { + location.reload(true); + } +}; + +export const redirectToIndex = message => { + if (message) { + errorAlert(message, false); + } + window.location.href = 'index.html'; +}; + +export const setDataInElement = (target, key, data) => { + target.dataset[`${key}`] = data; +}; + +export const getDataInElement = (target, key) => { + return target.dataset[`${key}`]; +}; + +export const createDivEl = ({ id, className, content, background }) => { + const el = document.createElement('div'); + if (id) { + el.id = id; + } + if (className) { + el.className = Array.isArray(className) ? className.join(' ') : className; + } + if (content) { + el.innerHTML = content; + } + if (background) { + el.style.backgroundImage = `url(${background})`; + } + return el; +}; + +export const isScrollBottom = target => { + return target.scrollTop + target.offsetHeight >= target.scrollHeight; +}; + +export const appendToFirst = (target, newElement) => { + if (target.childNodes.length > 0) { + target.insertBefore(newElement, target.childNodes[0]); + } else { + target.appendChild(newElement); + } +}; + +const hasClass = (target, className) => { + return target.classList + ? target.classList.contains(className) + : new RegExp('(^| )' + className + '( |$)', 'gi').test(target.className); +}; + +export const addClass = (target, className) => { + if (target.classList) { + if (!(className in target.classList)) { + target.classList.add(className); + } + } else { + if (target.className.indexOf(className) < 0) { + target.className += ` ${className}`; + } + } +}; + +export const removeClass = (target, className) => { + if (target.classList) { + target.classList.remove(className); + } else { + target.className = target.className.replace( + new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), + '' + ); + } +}; + +export const toggleClass = (target, className) => { + hasClass(target, className) ? removeClass(target, className) : addClass(target, className); +}; + +export const uuid4 = () => { + let d = new Date().getTime(); + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + const r = (d + Math.random() * 16) % 16 | 0; + d = Math.floor(d / 16); + return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16); + }); +}; + +export const protectFromXSS = text => { + return typeof text === 'string' + ? text + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, ''') + : text; +}; diff --git a/javascript/javascript-basic-local-caching/src/scss/_animation.scss b/javascript/javascript-basic-local-caching/src/scss/_animation.scss new file mode 100644 index 00000000..75dad441 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/_animation.scss @@ -0,0 +1,40 @@ +// Mixin +@mixin keyframes($name) { + @-webkit-keyframes #{$name} { @content; } + @-moz-keyframes #{$name} { @content; } + @-o-keyframes #{$name} { @content; } + @-ms-keyframes #{$name} { @content; } + @keyframes #{$name} { @content; } +} + +@mixin transition($options...) { + -webkit-transition: $options; + -moz-transition: $options; + -ms-transition: $options; + -o-transition: $options; + transition: $options; +} + +@mixin transform-scale($size) { + -webkit-transform: scale($size); + -moz-transform: scale($size); + -ms-transform: scale($size); + -o-transform: scale($size); + transform: scale($size); +} + +@mixin animation($animation...) { + -webkit-animation: $animation; + -moz-animation: $animation; + -o-animation: $animation; + -ms-animation: $animation; + animation: $animation; +} + +@mixin animation-delay($delay) { + -webkit-animation-delay: $delay; + -moz-animation-delay: $delay; + -o-animation-delay: $delay; + -ms-animation-delay: $delay; + animation-delay: $delay; +} diff --git a/javascript/javascript-basic-local-caching/src/scss/_common.scss b/javascript/javascript-basic-local-caching/src/scss/_common.scss new file mode 100644 index 00000000..9727b042 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/_common.scss @@ -0,0 +1,10 @@ +@import 'normalize'; +@import 'variables'; +@import 'mixins'; +@import 'icons'; + +body { + display: flex; + font-family: $font-family-exo2; + -webkit-font-smoothing: antialiased; +} diff --git a/javascript/javascript-basic-local-caching/src/scss/_icons.scss b/javascript/javascript-basic-local-caching/src/scss/_icons.scss new file mode 100644 index 00000000..01c41b28 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/_icons.scss @@ -0,0 +1,40 @@ +// Icons +$ic-prefix: 'https://dxstmhyqfqr1o.cloudfront.net/web-basic/'; +$ic-input-user: 'icon-username-landing.svg'; +$ic-profile-default: 'image-profile.svg'; +$ic-add-normal: 'icon-add-normal.png'; +$ic-add-over: 'icon-add-over.png'; +$ic-close: 'icon-close.png'; +$ic-enter: 'icon-enter.png'; +$ic-check-unselect: 'icon-check-unselect.png'; +$ic-check-select: 'icon-check-select.png'; +$ic-empty-chat: 'img-empty.svg'; + +$ic-group: 'icon-group.png'; +$ic-hide-normal: 'icon-hide-normal.png'; +$ic-hide: 'icon-hide.png'; +$ic-group-add-normal: 'icon-group-add-normal.png'; +$ic-group-add: 'icon-group-add.png'; +$ic-leave-normal: 'icon-leave-normal.png'; +$ic-leave: 'icon-leave.png'; +$ic-attach-file-normal: 'icon-attach-file-normal.png'; +$ic-attach-file: 'icon-attach-file.png'; +$ic-arrow-normal: 'icon-arrow-nomal.png'; +$ic-arrow: 'icon-arrow.png'; +$ic-back: 'icon-back.png'; + +$ic-search: 'icon-search-nomal.png'; +$ic-search-over: 'icon-search-over.png'; + +@mixin icon($url, $size: cover, $position: center) { + background-image: url($ic-prefix + $url); + background-position: $position; + background-size: $size; + background-repeat: no-repeat; +} + +@mixin imageMessage() { + background-position: center; + background-size: 160px 160px; + background-repeat: no-repeat; +} \ No newline at end of file diff --git a/javascript/javascript-basic-local-caching/src/scss/_mixins.scss b/javascript/javascript-basic-local-caching/src/scss/_mixins.scss new file mode 100644 index 00000000..a954ed4b --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/_mixins.scss @@ -0,0 +1,4 @@ +@import 'mixins/border-radius'; +@import 'mixins/state'; +@import 'mixins/transform'; +@import 'mixins/reset'; diff --git a/javascript/javascript-basic-local-caching/src/scss/_normalize.scss b/javascript/javascript-basic-local-caching/src/scss/_normalize.scss new file mode 100644 index 00000000..08e68694 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/_normalize.scss @@ -0,0 +1,450 @@ +/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */ + +/* Document + ========================================================================== */ + +/** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in + * IE on Windows Phone and in iOS. + */ + +html { + line-height: 1.15; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/* Sections + ========================================================================== */ + +/** + * Remove the margin in all browsers (opinionated). + */ + +body { + margin: 0; +} + +/** + * Add the correct display in IE 9-. + */ + +article, +aside, +footer, +header, +nav, +section { + display: block; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/* Grouping content + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + * 1. Add the correct display in IE. + */ + +figcaption, +figure, +main { + /* 1 */ + display: block; +} + +/** + * Add the correct margin in IE 8. + */ + +figure { + margin: 1em 40px; +} + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +pre { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/* Text-level semantics + ========================================================================== */ + +/** + * 1. Remove the gray background on active links in IE 10. + * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. + */ + +a { + background-color: transparent; /* 1 */ + -webkit-text-decoration-skip: objects; /* 2 */ +} + +/** + * 1. Remove the bottom border in Chrome 57- and Firefox 39-. + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} + +/** + * Prevent the duplicate application of `bolder` by the next rule in Safari 6. + */ + +b, +strong { + font-weight: inherit; +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct font style in Android 4.3-. + */ + +dfn { + font-style: italic; +} + +/** + * Add the correct background and color in IE 9-. + */ + +mark { + background-color: #ff0; + color: #000; +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + */ + +audio, +video { + display: inline-block; +} + +/** + * Add the correct display in iOS 4-7. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Remove the border on images inside links in IE 10-. + */ + +img { + border-style: none; +} + +/** + * Hide the overflow in IE. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change the font styles in all browsers (opinionated). + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font-family: sans-serif; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { + /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { + /* 1 */ + text-transform: none; +} + +/** + * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` + * controls in Android 4. + * 2. Correct the inability to style clickable types in iOS and Safari. + */ + +button, +html [type='button'], /* 1 */ +[type='reset'], +[type='submit'] { + -webkit-appearance: button; /* 2 */ +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type='button']::-moz-focus-inner, +[type='reset']::-moz-focus-inner, +[type='submit']::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +[type='button']:-moz-focusring, +[type='reset']:-moz-focusring, +[type='submit']:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Correct the padding in Firefox. + */ + +fieldset { + padding: 0.35em 0.75em 0.625em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * 1. Add the correct display in IE 9-. + * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Remove the default vertical scrollbar in IE. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10-. + * 2. Remove the padding in IE 10-. + */ + +[type='checkbox'], +[type='radio'] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type='number']::-webkit-inner-spin-button, +[type='number']::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type='search'] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. + */ + +[type='search']::-webkit-search-cancel-button, +[type='search']::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* Interactive + ========================================================================== */ + +/* + * Add the correct display in IE 9-. + * 1. Add the correct display in Edge, IE, and Firefox. + */ + +details, /* 1 */ +menu { + display: block; +} + +/* + * Add the correct display in all browsers. + */ + +summary { + display: list-item; +} + +/* Scripting + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + */ + +canvas { + display: inline-block; +} + +/** + * Add the correct display in IE. + */ + +template { + display: none; +} + +/* Hidden + ========================================================================== */ + +/** + * Add the correct display in IE 10-. + */ + +[hidden] { + display: none; +} diff --git a/javascript/javascript-basic-local-caching/src/scss/_variables.scss b/javascript/javascript-basic-local-caching/src/scss/_variables.scss new file mode 100644 index 00000000..346a8a67 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/_variables.scss @@ -0,0 +1,41 @@ +// Color +$color-transparent: transparent !default; + +$color-black-border: #2C2D30 !default; +$color-black: #000000 !default; +$color-black-text: #555555 !default; +$color-black-text-light: #abb8c4 !default; + +$color-gray-admin: #e8ecef !default; +$color-gray-dark: #dedede !default; +$color-gray: #e3e3e3 !default; +$color-gray-light: #F8F8F8 !default; + +$color-white: #ffffff !default; + +$color-blue-dark: #328fe6 !default; +$color-blue: #32c5e6 !default; + + +$color-purple-darker: #463c66 !default; +$color-purple-dark: #4E4273 !default; +$color-purple: #6e5baa !default; +$color-purple-light: #6742d6 !default; + +$color-purple-deep: #673AB7 !default; + +$color-purple-text-dark: #7F6DA0 !default; +$color-purple-text: #c7b0ff !default; +$color-purple-text-light: #A08DCE !default; + +$color-green-online: #00C853 !default; + +$color-red: #DC5960 !default; + +$color-chat-border: #e0e2e5 !default; +$color-chat-select: #f8f9fa !default; + +$color-message-not-sent: #e5e5e5; + +// Font +$font-family-exo2: 'Exo 2'; diff --git a/javascript/javascript-basic-local-caching/src/scss/chat-body.scss b/javascript/javascript-basic-local-caching/src/scss/chat-body.scss new file mode 100644 index 00000000..edfabbe2 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/chat-body.scss @@ -0,0 +1,35 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.chat-body { + display: flex; + flex-direction: column; + height: 100%; + max-height: calc(100vh - 180px); + overflow-y: auto; + overflow-x: hidden; + padding: 10px 0; + + & > .new-message-pop { + margin: 0px 10px; + display: flex; + width: inherit; + + position: sticky; + bottom: -10px; + background-color: $color-white; + border: 5px solid $color-blue; + border-radius: 10px; + + & > .new-message-pop-text { + margin-left: 30px; + height: 30px; + font-size: 24px; + color: $color-blue; + @include hover-focus { + cursor: pointer; + } + } + } +} diff --git a/javascript/javascript-basic-local-caching/src/scss/chat-input.scss b/javascript/javascript-basic-local-caching/src/scss/chat-input.scss new file mode 100644 index 00000000..089761eb --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/chat-input.scss @@ -0,0 +1,74 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.chat-input { + display: flex; + padding: 20px; + border-top: 1px solid $color-chat-border; + background-color: $color-white; + + & > .typing-field { + display: none; + position: absolute; + bottom: 79px; + left: 220px; + width: calc(100vw - 220px - 240px); + padding: 6px 20px; + box-sizing: border-box; + background-color: rgba(0, 0, 0, 0.1); + color: $color-black-text; + opacity: 0.4; + vertical-align: middle; + font-size: 13px; + font-style: italic; + } + + & > .input-file { + display: flex; + width: 36px; + height: 36px; + border: 1px solid $color-chat-border; + border-right: 0; + background-color: $color-white; + cursor: pointer; + @include border-left-radius(4px); + @include icon($ic-attach-file-normal, 20px 20px, center center); + @include hover-focus { + border: 1px solid $color-black-border; + @include icon($ic-attach-file, 20px 20px, center center); + } + } + + & > .input-text { + display: flex; + font-size: 15px; + width: 100%; + height: 38px; + padding: 7px 8px 6px 8px; + box-sizing: border-box; + border: 1px solid $color-chat-border; + background-color: $color-white; + @include border-right-radius(4px); + @include hover-focus-active { + border: 1px solid $color-black-border; + } + + & > .input-text-area { + width: 100%; + outline: none; + border: 0; + resize: none; + line-height: 1.4; + background-color: $color-white; + overflow: hidden; + @include hover-focus { + outline: none; + border: 0; + resize: none; + padding-top: 2px; + line-height: 1.4; + } + } + } +} diff --git a/javascript/javascript-basic-local-caching/src/scss/chat-main.scss b/javascript/javascript-basic-local-caching/src/scss/chat-main.scss new file mode 100644 index 00000000..34279652 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/chat-main.scss @@ -0,0 +1,18 @@ +@import 'mixins'; +@import 'variables'; + +.chat-main-root { + display: flex; + flex-direction: row; + height: 100%; + overflow-y: auto; + overflow-x: hidden; + padding: 0; + + & > .chat-main { + display: flex; + flex-direction: column; + justify-content: space-between; + width: 100%; + } +} diff --git a/javascript/javascript-basic-local-caching/src/scss/chat-menu.scss b/javascript/javascript-basic-local-caching/src/scss/chat-menu.scss new file mode 100644 index 00000000..b54403ae --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/chat-menu.scss @@ -0,0 +1,97 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.chat-menu-root { + display: flex; + flex-direction: column; + width: 240px; + min-width: 240px; + max-width: 240px; + background-color: $color-white; + box-sizing: border-box; + border-left: 1px solid $color-chat-border; + color: $color-black-border; + padding: 0; + + & > .menu-item { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + align-content: center; + padding: 10px 20px; + border-bottom: 1px solid $color-chat-border; + cursor: pointer; + + & > .menu-users, + & > .menu-blocked { + display: flex; + opacity: 0.6; + } + + & > .menu-arrow { + display: flex; + width: 36px; + height: 36px; + @include icon($ic-arrow-normal, 26px 26px, center center); + } + + @include hover-focus { + background-color: $color-chat-select; + + & > .menu-users, + & > .menu-blocked { + opacity: 1; + } + + & > .menu-arrow { + @include icon($ic-arrow, 26px 26px, center center); + } + } + } + + & > .menu-list { + display: none; + flex-direction: column; + position: absolute; + width: 239px; + height: calc(100% - 77px); + background: $color-white; + z-index: 999; + + & > .list-title { + display: flex; + align-items: center; + align-content: center; + padding: 10px 20px; + box-sizing: border-box; + color: $color-black-border; + border-bottom: 1px solid $color-chat-border; + cursor: pointer; + @include hover-focus { + background-color: $color-chat-select; + } + + & > .list-back { + display: flex; + width: 36px; + height: 36px; + @include icon($ic-back, 24px 24px, 0 center); + } + + & > .list-text { + display: flex; + } + } + + & > .list-body { + display: block; + flex-direction: column; + height: 100%; + max-height: calc(100% - 56px); + overflow-y: auto; + overflow-x: hidden; + } + } +} diff --git a/javascript/javascript-basic-local-caching/src/scss/chat-top-menu.scss b/javascript/javascript-basic-local-caching/src/scss/chat-top-menu.scss new file mode 100644 index 00000000..239bb56c --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/chat-top-menu.scss @@ -0,0 +1,81 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.chat-top { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + height: 80px; + box-sizing: border-box; + padding: 15px 20px; + border: 1px solid transparent; + border-bottom: 1px solid $color-chat-border; + color: $color-black-border; + + & > .chat-title { + max-width: 800px; + font-size: 20px; + white-space: nowrap; + overflow: hidden; + -ms-text-overflow: ellipsis; + text-overflow: ellipsis; + } + & > .chat-title.is-group { + padding-left: 34px; + @include icon($ic-group, 27px 27px, 0 center); + } + + & > .chat-button { + display: flex; + flex-direction: row; + justify-content: flex-end; + width: 150px; + margin-left: 20px; + + & > .button-invite { + width: 36px; + height: 36px; + border: 1px solid $color-chat-border; + margin-right: 10px; + cursor: pointer; + @include border-radius(4px); + @include icon($ic-group-add-normal, 20px 20px, center center); + @include hover-focus { + cursor: pointer; + border: 1px solid $color-black-border; + @include icon($ic-group-add, 20px 20px, center center); + } + } + + & > .button-hide { + width: 36px; + height: 36px; + border: 1px solid $color-chat-border; + margin-right: 10px; + cursor: pointer; + @include border-radius(4px); + @include icon($ic-hide-normal, 20px 20px, center center); + @include hover-focus { + cursor: pointer; + border: 1px solid $color-black-border; + @include icon($ic-hide, 20px 20px, center center); + } + } + + & > .button-leave { + width: 36px; + height: 36px; + border: 1px solid $color-chat-border; + cursor: pointer; + @include border-radius(4px); + @include icon($ic-leave-normal, 20px 20px, center center); + @include hover-focus { + cursor: pointer; + border: 1px solid $color-black-border; + @include icon($ic-leave, 20px 20px, center center); + } + } + } +} diff --git a/javascript/javascript-basic-local-caching/src/scss/chat-user-item.scss b/javascript/javascript-basic-local-caching/src/scss/chat-user-item.scss new file mode 100644 index 00000000..649deefb --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/chat-user-item.scss @@ -0,0 +1,34 @@ +@import 'mixins'; +@import 'variables'; + +.chat-user-item { + display: flex; + flex-direction: row; + align-items: center; + padding: 10px 20px; + cursor: pointer; + + & > .user-image { + display: flex; + width: 36px; + height: 36px; + margin-right: 10px; + background-size: 36px 36px; + background-position: center center; + background-repeat: no-repeat; + @include border-radius(50%); + } + + & > .user-nickname { + width: 154px; + max-width: 154px; + white-space: nowrap; + overflow: hidden; + -ms-text-overflow: ellipsis; + text-overflow: ellipsis; + } + & > .user-nickname.is-user { + font-weight: 600; + color: $color-purple-deep; + } +} diff --git a/javascript/javascript-basic-local-caching/src/scss/chat.scss b/javascript/javascript-basic-local-caching/src/scss/chat.scss new file mode 100644 index 00000000..9c9242ae --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/chat.scss @@ -0,0 +1,51 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.chat-empty { + display: flex; + width: 100%; + height: 100%; + + & > .empty-content { + display: flex; + flex-direction: column; + align-items: center; + margin: auto; + text-align: center; + color: $color-black-text-light; + @include transform-translate(0, -50%); + + & > .content-title { + display: flex; + font-size: 28px; + } + + & > .content-image { + display: flex; + width: 80px; + height: 80px; + padding: 8px; + @include icon($ic-empty-chat, 80px 80px, center center); + } + + & > .content-desc { + display: flex; + font-size: 14px; + white-space: pre; + } + } +} + +.logo-image { + background-color: $color-white; + border-radius: 50%; +} + +.chat-root { + display: flex; + flex-direction: column; + justify-content: flex-start; + width: 100%; + height: 100%; +} diff --git a/javascript/javascript-basic-local-caching/src/scss/index.scss b/javascript/javascript-basic-local-caching/src/scss/index.scss new file mode 100644 index 00000000..c504b226 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/index.scss @@ -0,0 +1,146 @@ +@import 'common'; + +body { + background-color: $color-purple; +} + +.logo-image { + background-color: $color-white; + border-radius: 50%; +} + +.container { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + min-width: 900px; + min-height: 650px; + font-family: $font-family-exo2; + + &>.top { + display: flex; + justify-content: center; + align-items: center; + margin-top: 80px; + color: $color-white; + + &>.logo { + display: flex; + align-items: center; + background-color: $color-white; + width: 87px; + height: 87px; + flex-direction: column; + justify-content: center; + @include border-radius(50%); + + &>.logo-image { + display: flex; + align-items: center; + } + } + + &>.title { + display: flex; + align-items: center; + + &>.title-company { + display: flex; + align-items: center; + font-size: 30px; + font-weight: 600; + margin: 0 10px; + } + + &>.title-desc { + display: flex; + align-items: center; + font-size: 26px; + font-weight: 200; + } + } + } + + &>.login { + display: flex; + margin-top: 40px; + flex-direction: column; + justify-content: center; + align-items: center; + + &>.desc { + display: flex; + color: $color-purple-text; + flex-direction: column; + align-items: center; + text-align: center; + + &>.download { + display: flex; + text-align: center; + margin: 20px 0; + + &>.download-sample { + color: $color-purple-text; + cursor: pointer; + + @include hover { + cursor: pointer; + } + } + } + } + + &>.form { + display: flex; + flex-direction: column; + margin-top: 10px; + + &>.form-input { + display: flex; + margin-top: 10px; + border: 2px solid $color-white; + padding: 0 10px 0 40px; + width: 300px; + height: 50px; + font-size: 16px; + color: $color-black-text; + @include border-radius(2px); + @include icon($ic-input-user, 20px 20px, 10px center); + + @include hover-focus { + border: 2px solid $color-blue; + } + } + + &>.button { + display: flex; + justify-content: center; + margin-top: 10px; + width: 100%; + height: 48px; + background-color: $color-blue; + color: $color-white; + font-size: 16px; + font-weight: 700; + border: 0; + @include border-radius(2px); + cursor: pointer; + + @include hover { + cursor: pointer; + } + } + } + } + + &>.image { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + margin-top: 50px; + color: $color-white; + } +} \ No newline at end of file diff --git a/javascript/javascript-basic-local-caching/src/scss/list-item.scss b/javascript/javascript-basic-local-caching/src/scss/list-item.scss new file mode 100644 index 00000000..a476e87f --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/list-item.scss @@ -0,0 +1,84 @@ +@import 'mixins'; +@import 'variables'; + +.list-item { + display: flex; + flex-direction: column; + padding: 6px 20px; + cursor: pointer; + @include hover { + background-color: $color-purple-darker; + } + & > .item-top { + display: flex; + color: $color-purple-text-light; + & > .item-count { + width: 18px; + height: 18px; + box-sizing: border-box; + border: 1px solid $color-purple-text-light; + align-items: center; + align-content: center; + text-align: center; + margin-right: 8px; + font-size: 13px; + line-height: 17px; + } + & > .item-title { + width: 100%; + max-width: 150px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + } + } + & > .item-bottom { + display: flex; + color: $color-purple-text-dark; + justify-content: space-between; + flex-direction: column; + font-size: 14px; + margin-top: 4px; + padding-left: 26px; + & > .item-message { + display: flex; + flex-direction: row; + justify-content: space-between; + & > .item-message-text { + width: 130px; + max-width: 130px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + color: $color-purple-text-light; + opacity: 0.7; + } + & > .item-message-unread { + display: none; + width: 16px; + height: 16px; + background-color: $color-red; + text-align: center; + color: $color-white; + font-size: 10px; + font-weight: 600; + line-height: 16px; + @include border-radius(50%); + } + & > .item-message-unread.active { + display: block; + } + } + & > .item-time { + display: flex; + font-size: 11px; + } + } +} + +.list-item.active { + & > .item-top { + color: $color-purple-text; + font-weight: 600; + } +} diff --git a/javascript/javascript-basic-local-caching/src/scss/list.scss b/javascript/javascript-basic-local-caching/src/scss/list.scss new file mode 100644 index 00000000..7365ce94 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/list.scss @@ -0,0 +1,106 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.list-root { + min-width: 980px; + width: 100vw; + height: 100vh; + max-height: 100vh; + overflow: hidden; + position: absolute; + z-index: 9999; + background-color: $color-white; + font-family: $font-family-exo2; + & > .list-body { + max-width: 700px; + min-width: 500px; + width: 100%; + height: 100%; + margin: 70px auto 50px auto; + display: flex; + box-sizing: border-box; + flex-direction: column; + & > .list-top { + width: 100%; + height: 70px; + padding: 10px 20px; + box-sizing: border-box; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + & > .list-title { + display: flex; + font-size: 30px; + font-weight: 700; + margin-left: 20px; + } + & > .list-button { + display: flex; + flex-direction: row; + margin-right: 20px; + + & > .button-exit { + width: 36px; + height: 36px; + text-align: center; + justify-content: center; + display: flex; + line-height: 36px; + cursor: pointer; + border: 1px solid $color-black-border; + @include border-radius(4px); + @include icon($ic-close, 20px 20px, center center); + @include hover-focus { + cursor: pointer; + border: 1px solid $color-gray; + background-color: $color-gray; + } + } + } + } + & > .list-hr { + height: 0; + margin: 8px 20px; + border-top: 1px solid $color-gray; + } + + & > .list-search { + box-sizing: border-box; + padding: 10px 20px; + overflow: hidden; + & > .search-input { + font-size: 18px; + font-family: $font-family-exo2; + box-sizing: border-box; + width: calc(100% - 40px); + height: 42px; + margin: 0 20px; + padding-left: 44px; + outline: none; + border: 1px solid $color-gray; + @include border-radius(4px); + @include icon($ic-search, 26px 26px, 8px center); + @include hover-focus { + @include icon($ic-search-over, 26px 26px, 8px center); + border: 1px solid $color-purple-light; + font-weight: 300; + } + &::placeholder { + color: $color-gray; + font-size: 18px; + font-weight: 300; + } + } + } + + & > .list-content { + box-sizing: border-box; + padding: 10px 20px; + max-height: calc(100vh - 205px); + overflow-y: auto; + overflow-x: hidden; + } + } +} diff --git a/javascript/javascript-basic-local-caching/src/scss/main.scss b/javascript/javascript-basic-local-caching/src/scss/main.scss new file mode 100644 index 00000000..bc07b2e2 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/main.scss @@ -0,0 +1,163 @@ +@import 'common'; + +.body { + display: flex; + flex-direction: row; + width: 100%; + min-width: 980px; + font-family: $font-family-exo2; + + &>.body-left { + display: flex; + flex-direction: column; + justify-content: space-between; + width: 220px; + height: 100vh; + background-color: $color-purple-dark; + + &>.body-left-top { + display: flex; + padding: 20px; + justify-content: center; + + &>.top-logo { + display: flex; + align-items: center; + background-color: $color-white; + width: 50px; + height: 50px; + flex-direction: column; + justify-content: center; + @include border-radius(50%); + + &>.logo-image { + display: flex; + align-items: center; + } + } + + &>.top-text { + color: $color-white; + display: flex; + align-items: center; + font-size: 30px; + font-weight: 600; + margin-left: 5px; + } + } + + &>.body-left-list { + display: flex; + flex-direction: column; + height: calc(100vh - 170px); + color: $color-purple-text-dark; + + .icon-create-chat { + width: 20px; + height: 20px; + @include border-radius(4px); + @include icon($ic-add-normal, 17px 17px, center center); + + @include hover { + cursor: pointer; + background-color: $color-purple-text-light; + } + } + + &>.chat-type { + display: flex; + flex-direction: row; + justify-content: space-between; + font-family: $font-family-exo2; + font-weight: 400; + font-size: 14px; + color: #9F8DC0; + line-height: 20px; + padding: 8px 20px; + + &>.chat-type-title { + @include hover { + cursor: pointer; + font-weight: 600; + color: $color-purple-text-light; + } + } + } + + &>.chat-list { + flex-direction: column; + width: 100%; + max-height: 450px; + overflow-y: auto; + overflow-x: hidden; + box-sizing: border-box; + + &>.default-item { + display: block; + padding: 10px; + margin: 0 20px; + color: $color-purple-text-light; + font-size: 16px; + border: 1px dashed $color-purple-text-light; + @include border-radius(4px); + } + } + + &>.chat-list.chat-list-group { + max-height: calc(100% - 130px); + } + } + + &>.body-left-bottom { + display: flex; + padding: 20px; + background-color: $color-purple-darker; + + &>.bottom-profile { + display: flex; + height: 40px; + align-items: center; + + &>.image-profile { + display: flex; + align-items: center; + @include border-radius(50%); + } + } + + &>.bottom-nickname { + display: flex; + flex-direction: column; + justify-content: center; + padding-left: 10px; + + &>.nickname-title { + display: flex; + color: $color-purple-text-dark; + font-size: 14px; + } + + &>.nickname-content { + display: inline-block; + max-width: 150px; + height: 18px; + color: $color-purple-text-light; + font-size: 16px; + overflow: hidden; + text-overflow: ellipsis; + -ms-text-overflow: ellipsis; + white-space: nowrap; + } + } + } + } + + &>.body-center { + display: flex; + flex-direction: column; + width: 100%; + min-width: 500px; + height: 100%; + background-color: $color-white; + } +} \ No newline at end of file diff --git a/javascript/javascript-basic-local-caching/src/scss/message-delete-modal.scss b/javascript/javascript-basic-local-caching/src/scss/message-delete-modal.scss new file mode 100644 index 00000000..57c4db82 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/message-delete-modal.scss @@ -0,0 +1,14 @@ +@import 'mixins'; +@import 'variables'; + +.modal-message { + display: flex; + align-items: center; + padding: 10px 10px; + width: 100%; + border: 1px solid $color-red; + background-color: $color-white; + font-size: 18px; + margin: 10px 0; + @include border-radius(4px); +} diff --git a/javascript/javascript-basic-local-caching/src/scss/message.scss b/javascript/javascript-basic-local-caching/src/scss/message.scss new file mode 100644 index 00000000..e3f6d3ab --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/message.scss @@ -0,0 +1,113 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.chat-message { + display: block; + flex-direction: row; + justify-content: space-between; + align-items: center; + width: 100%; + box-sizing: border-box; + padding: 0 20px; + margin-bottom: 8px; + border: 1px solid transparent; + + & > .message-content { + display: inline; + & > .message-nickname { + align-items: center; + display: inline; + justify-content: flex-start; + flex-direction: column; + cursor: pointer; + } + & > .message-nickname.is-user { + font-weight: 600; + color: $color-purple-deep; + cursor: initial; + } + + & > .message-content { + display: inline; + white-space: pre-line; + } + & > .message-content.is-file { + cursor: pointer; + @include hover-focus { + color: $color-blue-dark; + } + } + + & > .time { + display: inline; + margin-left: 8px; + font-size: 12px; + opacity: 0.5; + } + & > .time.is-user { + cursor: pointer; + } + + & > .read { + display: none; + vertical-align: middle; + text-align: center; + width: 18px; + height: 18px; + line-height: 17px; + margin-left: 8px; + font-size: 12px; + color: $color-white; + font-weight: 500; + @include border-radius(50%); + background: $color-red; + } + & > .read.active { + display: inline-block; + } + & > .resend-button { + display: inline; + margin-left: 8px; + font-size: 12px; + cursor: pointer; + color: $color-red; + } + + & > .delete-button { + display: inline; + margin-left: 8px; + font-size: 12px; + cursor: pointer; + color: $color-red; + } + } + + & > .file-content { + display: block; + border-left: 2px solid $color-black-text; + padding-left: 10px; + margin-top: 8px; + cursor: pointer; + & > .file-render { + display: inline; + max-width: 300px; + max-height: 300px; + } + } + + & > .message-admin { + display: flex; + align-items: center; + width: 100%; + font-style: italic; + color: $color-black-text; + } +} + +.chat-message.is-failed { + background: $color-message-not-sent; +} +.chat-message.is-pending { + color: $color-message-not-sent; +} diff --git a/web-live-chat/src/scss/mixins/_border-radius.scss b/javascript/javascript-basic-local-caching/src/scss/mixins/_border-radius.scss similarity index 100% rename from web-live-chat/src/scss/mixins/_border-radius.scss rename to javascript/javascript-basic-local-caching/src/scss/mixins/_border-radius.scss diff --git a/web-live-chat/src/scss/mixins/_reset.scss b/javascript/javascript-basic-local-caching/src/scss/mixins/_reset.scss similarity index 100% rename from web-live-chat/src/scss/mixins/_reset.scss rename to javascript/javascript-basic-local-caching/src/scss/mixins/_reset.scss diff --git a/javascript/javascript-basic-local-caching/src/scss/mixins/_state.scss b/javascript/javascript-basic-local-caching/src/scss/mixins/_state.scss new file mode 100644 index 00000000..94e4cea3 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/mixins/_state.scss @@ -0,0 +1,58 @@ +@mixin hover { + &:hover { @content; } +} + +@mixin plain-hover { + &, + &:hover { @content; } +} + +@mixin focus { + &:focus { @content; } +} + +@mixin plain-focus { + &, + &:focus { @content; } +} + +@mixin hover-focus { + &:hover, + &:focus { @content; } +} + +@mixin plain-hover-focus { + &, + &:hover, + &:focus { @content; } +} + +@mixin hover-focus-active { + &:hover, + &:focus, + &:active { @content; } +} + +@mixin after { + &::after { + @content + } +} + +@mixin before { + &::before { + @content + } +} + +@mixin before-after { + &::after, &::before { + @content + } +} + +@mixin plain-before-after { + &, &::after, &::before { + @content + } +} diff --git a/web-live-chat/src/scss/mixins/_transform.scss b/javascript/javascript-basic-local-caching/src/scss/mixins/_transform.scss similarity index 100% rename from web-live-chat/src/scss/mixins/_transform.scss rename to javascript/javascript-basic-local-caching/src/scss/mixins/_transform.scss diff --git a/javascript/javascript-basic-local-caching/src/scss/modal.scss b/javascript/javascript-basic-local-caching/src/scss/modal.scss new file mode 100644 index 00000000..3590e65d --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/modal.scss @@ -0,0 +1,74 @@ +@import 'mixins'; +@import 'variables'; + +.modal-root { + display: flex; + position: absolute; + width: 100vw; + height: 100vh; + z-index: 9999; + background-color: rgba(0, 0, 0, 0.5); + + & > .modal-body { + display: flex; + flex-direction: column; + box-sizing: border-box; + width: 450px; + background-color: $color-white; + margin: auto; + padding: 24px; + @include border-radius(4px); + @include transform-translate(0, -50%); + + & > .modal-title { + display: flex; + font-size: 26px; + font-weight: 600; + margin-bottom: 8px; + } + + & > .modal-desc { + display: flex; + color: $color-black-text; + font-size: 14px; + font-weight: 300; + } + + & > .modal-content { + display: flex; + margin: 10px 0; + } + + & > .modal-bottom { + display: flex; + justify-content: flex-end; + & > .modal-cancel { + display: flex; + margin-right: 12px; + color: $color-black-text-light; + border: 1px solid $color-black-text-light; + cursor: pointer; + padding: 6px; + @include border-radius(4px); + @include hover-focus { + color: $color-purple-light; + border: 1px solid $color-purple-light; + } + } + & > .modal-submit { + display: flex; + color: $color-white; + background-color: $color-blue; + border: 1px solid $color-blue; + cursor: pointer; + padding: 6px; + font-weight: 600; + @include border-radius(4px); + @include hover-focus { + background-color: $color-blue-dark; + border: 1px solid $color-blue-dark; + } + } + } + } +} \ No newline at end of file diff --git a/javascript/javascript-basic-local-caching/src/scss/spinner.scss b/javascript/javascript-basic-local-caching/src/scss/spinner.scss new file mode 100644 index 00000000..7bf66632 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/spinner.scss @@ -0,0 +1,71 @@ +@import 'mixins'; +@import 'variables'; + +.sb-spinner { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + opacity: 0.6; + background-color: $color-white; + flex-direction: column; + justify-content: center; + display: flex; + + .sb-spinner-bubble { + color: $color-black; + font-size: 10px; + margin: 80px auto; + position: relative; + text-indent: -9999em; + -webkit-animation-delay: -0.16s; + animation-delay: -0.16s; + @include transform-translate(0, -2em); + @include plain-before-after { + @include border-radius(50%); + width: 1.5em; + height: 1.5em; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; + -webkit-animation: load7 1.8s infinite ease-in-out; + animation: load7 1.8s infinite ease-in-out; + } + @include before-after { + content: ''; + position: absolute; + top: 0; + } + @include before { + left: -3.5em; + -webkit-animation-delay: -0.32s; + animation-delay: -0.32s; + } + @include after { + left: 3.5em; + } + } + +} + +@-webkit-keyframes load7 { + 0%, + 80%, + 100% { + box-shadow: 0 2.5em 0 -1.3em; + } + 40% { + box-shadow: 0 2.5em 0 0; + } +} +@keyframes load7 { + 0%, + 80%, + 100% { + box-shadow: 0 2.5em 0 -1.3em; + } + 40% { + box-shadow: 0 2.5em 0 0; + } +} + diff --git a/javascript/javascript-basic-local-caching/src/scss/toast.scss b/javascript/javascript-basic-local-caching/src/scss/toast.scss new file mode 100644 index 00000000..112eaa3b --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/toast.scss @@ -0,0 +1,21 @@ +@import 'variables'; +@import 'animation'; + +.sb-toast { + position: fixed; + top: 0; + left: 0; + width: 100%; + text-align: center; + + .sb-toast-message { + color: $color-white; + display:inline-block; + font-size: 14px; + padding:10px 15px; + margin-top:20px; + border-radius:5px; + background-color: $color-purple-dark; + } +} + diff --git a/javascript/javascript-basic-local-caching/src/scss/user-block-modal.scss b/javascript/javascript-basic-local-caching/src/scss/user-block-modal.scss new file mode 100644 index 00000000..9df0631c --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/user-block-modal.scss @@ -0,0 +1,34 @@ +@import 'mixins'; +@import 'variables'; + +.modal-user { + display: flex; + align-items: center; + padding: 10px 10px; + width: 100%; + border: 1px solid $color-red; + background-color: $color-white; + font-size: 18px; + margin: 10px 0; + @include border-radius(4px); + + & > .user-profile { + display: flex; + width: 36px; + height: 36px; + margin-right: 10px; + background-size: 36px 36px; + background-position: center center; + background-repeat: no-repeat; + @include border-radius(50%); + } + + & > .user-nickname { + width: 330px; + max-width: 330px; + white-space: nowrap; + overflow: hidden; + -ms-text-overflow: ellipsis; + text-overflow: ellipsis; + } +} diff --git a/javascript/javascript-basic-local-caching/src/scss/user-item.scss b/javascript/javascript-basic-local-caching/src/scss/user-item.scss new file mode 100644 index 00000000..de417bfd --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/user-item.scss @@ -0,0 +1,77 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.user-item { + display: flex; + padding: 8px 20px 8px 20px; + border: 1px solid transparent; + border-bottom: 1px solid $color-gray-dark; + justify-content: space-between; + cursor: pointer; + @include hover-focus { + cursor: pointer; + border: 1px solid $color-purple-light; + @include border-radius(2px); + } + + & > .user-info { + display: flex; + align-items: center; + + & > .user-profile { + display: flex; + width: 40px; + height: 40px; + @include icon($ic-profile-default, 40px 40px, center center); + } + + & > .user-nickname { + margin: 0 10px; + font-size: 18px; + max-width: 250px; + overflow: hidden; + text-overflow: ellipsis; + -ms-text-overflow: ellipsis; + white-space: nowrap; + } + + & > .user-online { + display: flex; + width: 8px; + height: 8px; + border: 1px solid $color-black-text-light; + background-color: $color-black-text-light; + opacity: 0.4; + @include border-radius(50%); + } + & > .user-online.active { + border: 1px solid $color-green-online; + background-color: $color-green-online; + opacity: 1; + } + } + + & > .user-state { + display: flex; + align-items: center; + + & > .user-time { + display: flex; + color: $color-black-text-light; + margin-right: 10px; + } + + & > .user-select { + display: flex; + width: 30px; + height: 30px; + opacity: 0.4; + @include icon($ic-check-unselect, 30px 30px, center center); + } + & > .user-select.active { + opacity: 1; + @include icon($ic-check-select, 30px 30px, center center); + } + } +} diff --git a/javascript/javascript-basic-local-caching/src/scss/user-list.scss b/javascript/javascript-basic-local-caching/src/scss/user-list.scss new file mode 100644 index 00000000..bc99f7b4 --- /dev/null +++ b/javascript/javascript-basic-local-caching/src/scss/user-list.scss @@ -0,0 +1,23 @@ +@import 'mixins'; +@import 'variables'; + +.button-create { + width: 80px; + height: 36px; + text-align: center; + justify-content: center; + display: flex; + line-height: 36px; + font-weight: 600; + color: $color-white; + cursor: pointer; + background-color: $color-blue; + border: 1px solid $color-blue; + margin-right: 12px; + @include border-radius(4px); + @include hover-focus { + cursor: pointer; + background-color: $color-blue-dark; + border: 1px solid $color-blue-dark; + } +} diff --git a/javascript/javascript-basic-local-caching/webpack.config.js b/javascript/javascript-basic-local-caching/webpack.config.js new file mode 100644 index 00000000..a33ab0a6 --- /dev/null +++ b/javascript/javascript-basic-local-caching/webpack.config.js @@ -0,0 +1,79 @@ +'use strict'; +const path = require('path'); +const ExtractTextPlugin = require('extract-text-webpack-plugin'); + +const PRODUCTION = 'production'; + +module.exports = () => { + const config = { + mode: 'production', + entry: { + index: ['./src/js/index.js', './src/scss/index.scss'], + main: ['./src/js/main.js', './src/scss/main.scss'] + }, + output: { + path: path.resolve(__dirname, './dist'), + filename: 'sample.[name].js', + library: '[name]', + libraryExport: 'default', + libraryTarget: 'umd', + publicPath: 'dist' + }, + devtool: 'cheap-eval-source-map', + devServer: { + publicPath: '/dist/', + compress: true, + port: 9000 + }, + performance: { hints: false }, + module: { + rules: [ + { + // SCSS/SASS + test: /\.s[ac]ss$/i, + use: ExtractTextPlugin.extract({ + fallback: 'style-loader', + use: [ + { + loader: 'css-loader', + options: { + module: true, + minimize: process.env.WEBPACK_MODE === PRODUCTION, + // sourceMap: true, + localIdentName: '[local]' + } + }, + { + loader: 'sass-loader', + options: { + implementation: require("sass"), + } + } + ] + }) + }, + { + // ESLint + enforce: 'pre', + test: /\.js$/, + exclude: /node_modules/, + loader: 'eslint-loader', + options: { failOnError: true } + }, + { + // ES6 + test: /\.js$/, + loader: 'babel-loader', + exclude: '/node_modules/' + } + ] + }, + plugins: [ + new ExtractTextPlugin({ + filename: 'sample.[name].css' + }) + ] + }; + + return config; +}; diff --git a/javascript/javascript-basic-syncmanager/.babelrc b/javascript/javascript-basic-syncmanager/.babelrc new file mode 100644 index 00000000..a7352030 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/.babelrc @@ -0,0 +1,8 @@ +{ + "presets": ["env"], + "env": { + "test": { + "presets": ["env"] + } + } +} diff --git a/javascript/javascript-basic-syncmanager/.eslintignore b/javascript/javascript-basic-syncmanager/.eslintignore new file mode 100644 index 00000000..feb309d8 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/.eslintignore @@ -0,0 +1,2 @@ + +**/*.min.js \ No newline at end of file diff --git a/javascript/javascript-basic-syncmanager/.eslintrc.js b/javascript/javascript-basic-syncmanager/.eslintrc.js new file mode 100644 index 00000000..0211a4b2 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/.eslintrc.js @@ -0,0 +1,21 @@ +module.exports = { + env: { + browser: true, + commonjs: true, + es6: true + }, + extends: 'eslint:recommended', + parserOptions: { + parser: 'babel-eslint', + sourceType: 'module' + }, + rules: { + 'linebreak-style': ['error', 'unix'], + quotes: ['warn', 'single'], + semi: ['warn', 'always'], + 'no-console': 1, + 'no-unused-vars': 1, + 'no-inner-declarations': 1, + 'no-useless-escape': 1 + } +}; diff --git a/javascript/javascript-basic-syncmanager/.prettierignore b/javascript/javascript-basic-syncmanager/.prettierignore new file mode 100644 index 00000000..52999c0b --- /dev/null +++ b/javascript/javascript-basic-syncmanager/.prettierignore @@ -0,0 +1,2 @@ +README.md +.eslintrc.js \ No newline at end of file diff --git a/javascript/javascript-basic-syncmanager/.prettierrc b/javascript/javascript-basic-syncmanager/.prettierrc new file mode 100644 index 00000000..f65aabcb --- /dev/null +++ b/javascript/javascript-basic-syncmanager/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "printWidth": 120 +} \ No newline at end of file diff --git a/javascript/javascript-basic-syncmanager/README.md b/javascript/javascript-basic-syncmanager/README.md new file mode 100644 index 00000000..845d7e55 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/README.md @@ -0,0 +1,87 @@ +# Sendbird SyncManager for JavaScript sample +![Platform](https://img.shields.io/badge/platform-JAVASCRIPT-orange.svg) +![Languages](https://img.shields.io/badge/language-JAVASCRIPT-orange.svg) +[![npm](https://img.shields.io/npm/v/sendbird-syncmanager.svg?style=popout&colorB=red)](https://www.npmjs.com/package/sendbird-syncmanager) + +## Introduction + +SyncManager for Javascript is a Chat SDK add-on that optimizes the user caching experience by interlinking the synchronization of the local data storage with the chat data in Sendbird server through an event-driven structure. Provided here is a SyncManager sample for Javascript to experience first-hand the benefits of Sendbird’s SyncManager. + +### Benefits + +Sendbird SyncManager provides the local caching system and data synchronization with the Sendbird server, which are run on an event-driven structure. According to the real-time events of the messages and channels, SyncManager takes care of the background tasks for the cache updates from the Sendbird server to the local device. By leveraging this systemized structure with connection-based synchronization, SyncManager allows you to easily integrate the Chat SDK to utilize all of its features, while also reducing data usage and offering a reliable and effortless storage mechanism. + +### More about Sendbird SyncManager for JavaScript + +Find out more about Sendbird SyncManager for JavaScript at [SyncManager for JavaScript doc](https://sendbird.com/docs/syncmanager/v1/javascript/getting-started/about-syncmanager). If you need any help in resolving any issues or have questions, visit [our community](https://community.sendbird.com). + +
+ +## Before getting started +This section provides the prerequisites for testing Sendbird Desk for Javascript sample app. + +### Requirements +The minimum requirements for SyncManager for Javascript are: +- Node. js v8+ +- NPM v6+ +- [Chat SDK for JavaScript](https://github.com/sendbird/SendBird-SDK-JavaScript) v3.0 115+ + +### Try the sample app using your data + +If you would like to try the sample app specifically fit to your usage, you can do so by replacing the default sample app ID with yours, which you can obtain by [creating your Sendbird application from the dashboard](https://sendbird.com/docs/chat/v3/javascript/getting-started/install-chat-sdk#2-step-1-create-a-sendbird-application-from-your-dashboard). Furthermore, you could also add data of your choice on the dashboard to test. This will allow you to experience the sample app with data from your Sendbird application. + +### Try the SyncManager on our demo website + +By using this [link](https://sample.sendbird.com/basic/sync-manager), you can test the SyncManager through our demo website. + +
+ +## Getting started + +You can install and run SyncManager for JavaScript sample app on your system using `npm`. + +### Install packages + +`Node` v8.x+ should be installed on your system. + +> `node-sass` package requires XCode developer tools (MacOS only) and Node.js version matching. If you have any trouble in the installation, see https://www.npmjs.com/package/node-sass. + +```bash +npm install +``` + +### Run the sample + +```bash +npm start +``` + +
+ +## Customizing the sample + +To implement customization to the sample, you can use `webpack` for buiding it. + +### Install packages + +`Node` v8.x+ should be installed on your system. + +```bash +npm install +``` + +### Modify files + +If you want to change `APP_ID`, change `APP_ID` in `const.js` to the other `APP_ID` you want. You can test the sample with local server by running the following command. + +```bash +npm run start:dev +``` + +### Build the sample + +When the modification is complete, you'll need to bundle the file using `webpack`. The bundled files are created in the **dist** folder. Please check `webpack.config.js` for settings. + +```bash +npm run build +``` diff --git a/javascript/javascript-basic-syncmanager/chat.html b/javascript/javascript-basic-syncmanager/chat.html new file mode 100644 index 00000000..01169d0b --- /dev/null +++ b/javascript/javascript-basic-syncmanager/chat.html @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + Basic Sample with SyncManager | Sendbird + + + +
+
+
+ +
+ Sendbird +
+
+
+
+
GROUP CHAT
+
+
+
+
+
+
Start by inviting user to create a channel.
+
+
+
+
+ +
+
+
username
+
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/javascript/javascript-basic-syncmanager/index.html b/javascript/javascript-basic-syncmanager/index.html new file mode 100644 index 00000000..e5745b1e --- /dev/null +++ b/javascript/javascript-basic-syncmanager/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + Basic Sample with SyncManager | Sendbird + + + +
+
+ +
+
+ Sendbird +
+
+ Web Basic Sample with SyncManager +
+
+
+ +
+
+ Start chatting on Sendbird by choosing your display name. +
This can be changed anytime and will be shown on 1-on-1 and group messaging. + +
+
+ + + +
+
+ +
+ +
+
+ + + + diff --git a/javascript/javascript-basic-syncmanager/package.json b/javascript/javascript-basic-syncmanager/package.json new file mode 100644 index 00000000..d16575b0 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/package.json @@ -0,0 +1,40 @@ +{ + "name": "Sample-JS-Web-Basic-SyncManager", + "version": "1.0.4", + "description": "Sendbird Web Basic Sample using SyncManager", + "main": "index.js", + "scripts": { + "dev": "./node_modules/.bin/webpack --mode=development", + "dev:w": "./node_modules/.bin/webpack --mode=none -w", + "build": "./node_modules/.bin/webpack --mode=production", + "start:dev": "./node_modules/.bin/webpack-dev-server", + "start": "npm run build && node server.js", + "deploy": "node ./deploy/deploy.js" + }, + "author": "SendBird", + "license": "ISC", + "devDependencies": { + "babel-core": "^6.26.0", + "babel-eslint": "^8.2.3", + "babel-loader": "^7.1.4", + "babel-preset-env": "^1.6.1", + "css-loader": "^0.28.11", + "eslint": "^4.19.1", + "eslint-loader": "^2.1.1", + "express": "^4.16.3", + "extract-text-webpack-plugin": "^4.0.0-beta.0", + "node-sass": "^4.9.3", + "prettier": "^1.14.3", + "sass-loader": "^7.0.1", + "ssh2": "^0.8.5", + "style-loader": "^0.21.0", + "webpack": "^4.19.1", + "webpack-cli": "^3.1.0", + "webpack-dev-server": "^3.1.11" + }, + "dependencies": { + "moment": "^2.22.1", + "sendbird": "^3.0.111", + "sendbird-syncmanager": "^1.1.14" + } +} diff --git a/javascript/javascript-basic-syncmanager/server.js b/javascript/javascript-basic-syncmanager/server.js new file mode 100644 index 00000000..487ba47b --- /dev/null +++ b/javascript/javascript-basic-syncmanager/server.js @@ -0,0 +1,14 @@ +const express = require('express'); +const app = express(); + +const PORT = 9000; + +app.use(express.static('dist')); +app.use(express.static('./')); + +app.get('/', function(req, res) { + res.sendfile('index.html'); +}); + +app.listen(PORT); +console.log(`[SERVER RUNNING] 127.0.0.1:${PORT}`); diff --git a/javascript/javascript-basic-syncmanager/src/js/Chat.js b/javascript/javascript-basic-syncmanager/src/js/Chat.js new file mode 100644 index 00000000..0cdf9fa9 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/Chat.js @@ -0,0 +1,120 @@ +import styles from '../scss/chat.scss'; +import { createDivEl } from './utils'; +import { SendBirdAction } from './SendBirdAction'; +import { SendBirdChatEvent } from './SendBirdChatEvent'; +import { ChatLeftMenu } from './ChatLeftMenu'; +import { ChatTopMenu } from './components/ChatTopMenu'; +import { ChatMain } from './components/ChatMain'; + +let instance = null; + +class Chat { + constructor() { + if (instance) { + return instance; + } + this.body = document.querySelector('.body-center'); + + this.channel = null; + this.element = null; + this.top = null; + this.emptyElement = this._createEmptyElement(); + this.render(); + instance = this; + } + + _createEmptyElement() { + const item = createDivEl({ className: styles['chat-empty'] }); + + const content = createDivEl({ className: styles['empty-content'] }); + item.appendChild(content); + + const title = createDivEl({ className: styles['content-title'], content: 'WELCOME TO SAMPLE CHAT' }); + content.appendChild(title); + const image = createDivEl({ className: styles['content-image'] }); + content.appendChild(image); + const desc = createDivEl({ + className: styles['content-desc'], + content: + 'Create or select a channel to chat in.\n' + + "If you don't have a channel to participate,\n" + + 'go ahead and create your first channel now.' + }); + content.appendChild(desc); + return item; + } + + renderEmptyElement() { + this._removeChatElement(); + this.body.appendChild(this.emptyElement); + } + + _removeEmptyElement() { + if (this.body.contains(this.emptyElement)) { + this.body.removeChild(this.emptyElement); + } + } + + _createChatElement(channel) { + this.element = createDivEl({ className: styles['chat-root'] }); + + this.top = new ChatTopMenu(channel); + this.element.appendChild(this.top.element); + + /// reset manager when ChatMain is obsolete + if (this.main && this.main.body && this.main.body.collection) { + this.main.body.collection.remove(); + } + this.main = new ChatMain(channel); + } + + _addEventHandler() { + const channelEvent = new SendBirdChatEvent(); + channelEvent.onTypingStatusUpdated = groupChannel => { + if (this.channel.url === groupChannel.url) { + this.main.updateTyping(groupChannel.getTypingMembers()); + } + }; + } + + _renderChatElement(channel) { + const sendbirdAction = SendBirdAction.getInstance(); + this._removeEmptyElement(); + this._removeChatElement(); + this.channel = channel; + + ChatLeftMenu.getInstance().activeChannelItem(channel.url); + this._addEventHandler(); + + sendbirdAction + .getChannel(channel.url) + .then(channel => { + this.channel = channel; + this._createChatElement(this.channel); + this.body.appendChild(this.element); + this.main.loadInitialMessages(); + }) + .catch(() => { + this._createChatElement(this.channel); + this.body.appendChild(this.element); + this.main.loadInitialMessages(); + }); + } + + _removeChatElement() { + const chatElements = this.body.getElementsByClassName(styles['chat-root']); + Array.prototype.slice.call(chatElements).forEach(chatEl => { + chatEl.parentNode.removeChild(chatEl); + }); + } + + render(channel) { + channel ? this._renderChatElement(channel) : this.renderEmptyElement(); + } + + static getInstance() { + return new Chat(); + } +} + +export { Chat }; diff --git a/javascript/javascript-basic-syncmanager/src/js/ChatLeftMenu.js b/javascript/javascript-basic-syncmanager/src/js/ChatLeftMenu.js new file mode 100644 index 00000000..b9a4ffbc --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/ChatLeftMenu.js @@ -0,0 +1,180 @@ +import { LeftListItem } from './components/LeftListItem'; +import { ACTIVE_CLASSNAME, DISPLAY_BLOCK, DISPLAY_NONE } from './const'; +import { addClass, isScrollBottom, isUrl, protectFromXSS, removeClass, findChannelIndex } from './utils'; +import { SendBirdAction } from './SendBirdAction'; +import { UserList } from './components/UserList'; +import { Chat } from './Chat'; + +import SendBirdSyncManager from 'sendbird-syncmanager'; + +let instance = null; + +class ChatLeftMenu { + constructor() { + if (instance) { + return instance; + } + this.activeChannelUrl = null; + + const action = new SendBirdAction(); + const query = action.sb.GroupChannel.createMyGroupChannelListQuery(); + query.limit = 50; + query.includeEmpty = false; + query.order = 'latest_last_message'; + + this.channelCollection = new SendBirdSyncManager.ChannelCollection(query); + const collectionHandler = new SendBirdSyncManager.ChannelCollection.CollectionHandler(); + collectionHandler.onChannelEvent = (action, channels) => { + switch (action) { + case 'insert': { + for (let i in channels) { + const channel = channels[i]; + const index = findChannelIndex(channel, this.channelCollection.channels); + const handler = () => { + Chat.getInstance().render(channel, false); + this.activeChannelUrl = channel.url; + }; + const item = new LeftListItem({ channel, handler }); + if (index < this.groupChannelList.childNodes.length - 1) { + this.groupChannelList.insertBefore(item.element, this.groupChannelList.childNodes[index]); + } else { + this.groupChannelList.appendChild(item.element); + } + if (this.activeChannelUrl === channel.url) { + this.activeChannelItem(channel.url); + } + } + LeftListItem.updateUnreadCount(); + this.toggleGroupChannelDefaultItem(); + break; + } + case 'update': { + for (let i in channels) { + const channel = channels[i]; + const item = this.getItem(channel.url); + const handler = () => { + Chat.getInstance().render(channel, false); + this.activeChannelUrl = channel.url; + }; + const newItem = new LeftListItem({ channel, handler }); + this.groupChannelList.replaceChild(newItem.element, item); + if (this.activeChannelUrl === channel.url) { + this.activeChannelItem(channel.url); + } + } + LeftListItem.updateUnreadCount(); + break; + } + case 'move': { + for (let i in channels) { + const channel = channels[i]; + const previousElement = this.getItem(channel.url); + this.groupChannelList.removeChild(previousElement); + + const handler = () => { + channel.markAsRead(); + Chat.getInstance().render(channel, false); + this.activeChannelUrl = channel.url; + }; + const newItem = new LeftListItem({ channel, handler }); + const index = findChannelIndex(channel, this.channelCollection.channels); + if (index < this.groupChannelList.childNodes.length - 1) { + this.groupChannelList.insertBefore(newItem.element, this.groupChannelList.childNodes[index]); + } else { + this.groupChannelList.appendChild(newItem.element); + } + if (this.activeChannelUrl === channel.url) { + this.activeChannelItem(channel.url); + } + } + LeftListItem.updateUnreadCount(); + break; + } + case 'remove': { + for (let i in channels) { + const channel = channels[i]; + if (this.activeChannelUrl === channel.url) { + this.activeChannelUrl = null; + Chat.getInstance().render(); + } + const element = this.getItem(channel.url); + this.groupChannelList.removeChild(element); + } + this.toggleGroupChannelDefaultItem(); + break; + } + case 'clear': { + if (this.activeChannelUrl) { + Chat.getInstance().render(); + } + this.activeChannelUrl = null; + const elements = this.groupChannelList.getElementsByClassName(LeftListItem.getItemRootClassName()); + for (let i in elements) { + this.groupChannelList.removeChild(elements[i]); + } + this.toggleGroupChannelDefaultItem(); + break; + } + } + }; + this.channelCollection.setCollectionHandler(collectionHandler); + + this.groupChannelList = document.getElementById('group_list'); + this.groupChannelList.addEventListener('scroll', () => { + if (isScrollBottom(this.groupChannelList)) { + this.loadGroupChannelList(); + } + }); + this.groupChannelDefaultItem = document.getElementById('default_item_group'); + + const groupChannelCreateBtn = document.getElementById('group_chat_add'); + groupChannelCreateBtn.addEventListener('click', () => { + UserList.getInstance().render(); + }); + instance = this; + } + + updateUserInfo(user) { + const userInfoEl = document.getElementById('user_info'); + const profileEl = userInfoEl.getElementsByClassName('image-profile')[0]; + if (isUrl(user.profileUrl)) { + profileEl.setAttribute('src', protectFromXSS(user.profileUrl)); + } + const nicknameEl = userInfoEl.getElementsByClassName('nickname-content')[0]; + nicknameEl.innerHTML = protectFromXSS(user.nickname); + } + + loadGroupChannelList() { + this.channelCollection.fetch(() => { + this.toggleGroupChannelDefaultItem(); + }); + } + getItem(elementId) { + const groupChannelItems = this.groupChannelList.getElementsByClassName(LeftListItem.getItemRootClassName()); + for (let i = 0; i < groupChannelItems.length; i++) { + if (groupChannelItems[i].id === elementId) { + return groupChannelItems[i]; + } + } + return null; + } + activeChannelItem(channelUrl) { + const groupItems = this.groupChannelList.getElementsByClassName(LeftListItem.getItemRootClassName()); + for (let i = 0; i < groupItems.length; i++) { + groupItems[i].id === channelUrl + ? addClass(groupItems[i], ACTIVE_CLASSNAME) + : removeClass(groupItems[i], ACTIVE_CLASSNAME); + } + } + toggleGroupChannelDefaultItem() { + this.groupChannelList.getElementsByClassName(LeftListItem.getItemRootClassName()).length > 0 + ? (this.groupChannelDefaultItem.style.display = DISPLAY_NONE) + : (this.groupChannelDefaultItem.style.display = DISPLAY_BLOCK); + } + + static getInstance() { + return new ChatLeftMenu(); + } +} + +export { ChatLeftMenu }; diff --git a/javascript/javascript-basic-syncmanager/src/js/SendBirdAction.js b/javascript/javascript-basic-syncmanager/src/js/SendBirdAction.js new file mode 100644 index 00000000..30392af5 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/SendBirdAction.js @@ -0,0 +1,237 @@ +import { APP_ID as appId } from './const'; +import { isNull } from './utils'; + +import SendBird from 'sendbird'; +import SendBirdSyncManager from 'sendbird-syncmanager'; + +let instance = null; + +class SendBirdAction { + constructor() { + if (instance) { + return instance; + } + this.sb = new SendBird({ + appId + }); + this.userQuery = null; + this.groupChannelQuery = null; + this.previousMessageQuery = null; + this.blockedQuery = null; + instance = this; + } + + /** + * Connect + */ + connect(userId, nickname) { + return new Promise((resolve, reject) => { + const sb = SendBird.getInstance(); + sb.connect(userId, (user, error) => { + if (error) { + reject(error); + } else { + sb.updateCurrentUserInfo(decodeURIComponent(nickname), null, (user, error) => { + error ? reject(error) : resolve(user); + }); + } + }); + }); + } + + /** + * User + */ + getCurrentUser() { + return this.sb.currentUser; + } + + getConnectionState() { + return this.sb.getConnectionState(); + } + + /** + * + * #################### SECURITY TIPS #################### + * Before launching, you should review "Allow retrieving user list from SDK" under ⚙️ Sendbird Dashboard ->Settings -> Security. + * It's turned on at first to simplify running samples and implementing your first code. + * Most apps will want to disable "Allow retrieving user list from SDK" as that could possibly expose user information + * #################### SECURITY TIPS #################### + * + */ + getUserList(isInit = false) { + if (isInit || isNull(this.userQuery)) { + this.userQuery = this.sb.createApplicationUserListQuery(); + this.userQuery.limit = 30; + } + return new Promise((resolve, reject) => { + if (this.userQuery.hasNext && !this.userQuery.isLoading) { + this.userQuery.next((list, error) => { + error ? reject(error) : resolve(list); + }); + } else { + resolve([]); + } + }); + } + + isCurrentUser(user) { + const manager = SendBirdSyncManager.getInstance(); + return user.userId === manager.currentUserId; + } + + getBlockedList(isInit = false) { + if (isInit || isNull(this.blockedQuery)) { + this.blockedQuery = this.sb.createBlockedUserListQuery(); + this.blockedQuery.limit = 30; + } + return new Promise((resolve, reject) => { + if (this.blockedQuery.hasNext && !this.blockedQuery.isLoading) { + this.blockedQuery.next((blockedList, error) => { + error ? reject(error) : resolve(blockedList); + }); + } else { + resolve([]); + } + }); + } + + blockUser(user, isBlock = true) { + return new Promise((resolve, reject) => { + if (isBlock) { + this.sb.blockUser(user, (response, error) => { + error ? reject(error) : resolve(); + }); + } else { + this.sb.unblockUser(user, (response, error) => { + error ? reject(error) : resolve(); + }); + } + }); + } + + /** + * Channel + */ + getChannel(channelUrl) { + return new Promise((resolve, reject) => { + this.sb.GroupChannel.getChannel(channelUrl, (groupChannel, error) => { + error ? reject(error) : resolve(groupChannel); + }); + }); + } + + /** + * + * #################### SECURITY TIPS #################### + * Before launching, you should review "Allow creating group channels from SDK" under ⚙️ Sendbird Dashboard -> Settings -> Security. + * It's turned on at first to simplify running samples and implementing your first code. + * Most apps will want to disable "Allow creating group channels from SDK" as that could cause unwanted operations. + * #################### SECURITY TIPS #################### + * + */ + createGroupChannel(userIds) { + return new Promise((resolve, reject) => { + let params = new this.sb.GroupChannelParams(); + params.addUserIds(userIds); + this.sb.GroupChannel.createChannel(params, (groupChannel, error) => { + error ? reject(error) : resolve(groupChannel); + }); + }); + } + + inviteGroupChannel(channelUrl, userIds) { + return new Promise((resolve, reject) => { + this.sb.GroupChannel.getChannel(channelUrl, (groupChannel, error) => { + if (error) { + reject(error); + } else { + groupChannel.inviteWithUserIds(userIds, (groupChannel, error) => { + error ? reject(error) : resolve(groupChannel); + }); + } + }); + }); + } + + leave(channelUrl) { + return new Promise((resolve, reject) => { + this.sb.GroupChannel.getChannel(channelUrl, (groupChannel, error) => { + if (error) { + reject(error); + } else { + groupChannel.leave((response, error) => { + error ? reject(error) : resolve(); + }); + } + }); + }); + } + + hide(channelUrl) { + return new Promise((resolve, reject) => { + this.sb.GroupChannel.getChannel(channelUrl, (groupChannel, error) => { + if (error) { + reject(error); + } else { + groupChannel.hide((response, error) => { + error ? reject(error) : resolve(); + }); + } + }); + }); + } + + markAsRead(channel) { + channel.markAsRead(); + } + + getReadReceipt(channel, message) { + if (this.isCurrentUser(message.sender)) { + return this.sb.currentUser ? channel.getReadReceipt(message) : 0; + } else { + return 0; + } + } + + sendUserMessage({ channel, message, handler }) { + return channel.sendUserMessage(message, (message, error) => { + if (handler) handler(message, error); + }); + } + + sendFileMessage({ channel, file, thumbnailSizes, handler }) { + const fileMessageParams = new this.sb.FileMessageParams(); + fileMessageParams.file = file; + fileMessageParams.thumbnailSizes = thumbnailSizes; + + return channel.sendFileMessage(fileMessageParams, (message, error) => { + if (handler) handler(message, error); + }); + } + + deleteMessage({ channel, message, col }) { + return new Promise((resolve, reject) => { + if (!this.isCurrentUser(message.sender)) { + reject({ + message: 'You have not ownership in this message.' + }); + return; + } + if (message.messageId === 0 && message.requestState === 'failed') { + col.deleteMessage(message); + resolve(true); + } else { + channel.deleteMessage(message, (response, error) => { + error ? reject(error) : resolve(response); + }); + } + }); + } + + static getInstance() { + return new SendBirdAction(); + } +} + +export { SendBirdAction }; diff --git a/javascript/javascript-basic-syncmanager/src/js/SendBirdChatEvent.js b/javascript/javascript-basic-syncmanager/src/js/SendBirdChatEvent.js new file mode 100644 index 00000000..8f12fd0e --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/SendBirdChatEvent.js @@ -0,0 +1,68 @@ +import { uuid4 } from './utils'; +import SendBird from 'sendbird'; + +let instance = null; + +class SendBirdChatEvent { + constructor() { + if (instance) { + return instance; + } + + this.sb = SendBird.getInstance(); + this.key = uuid4(); + this._createChannelHandler(); + + this.onMessageReceived = null; + this.onMessageUpdated = null; + this.onMessageDeleted = null; + + this.onReadReceiptUpdated = null; + this.onTypingStatusUpdated = null; + instance = this; + } + + /** + * Channel Handler + */ + _createChannelHandler() { + const handler = new this.sb.ChannelHandler(); + handler.onMessageReceived = (channel, message) => { + if (this.onMessageReceived) { + this.onMessageReceived(channel, message); + } + }; + handler.onMessageUpdated = (channel, message) => { + if (this.onMessageUpdated) { + this.onMessageUpdated(channel, message); + } + }; + handler.onMessageDeleted = (channel, messageId) => { + if (this.onMessageDeleted) { + this.onMessageDeleted(channel, messageId); + } + }; + + handler.onReadReceiptUpdated = groupChannel => { + if (this.onReadReceiptUpdated) { + this.onReadReceiptUpdated(groupChannel); + } + }; + handler.onTypingStatusUpdated = groupChannel => { + if (this.onTypingStatusUpdated) { + this.onTypingStatusUpdated(groupChannel); + } + }; + this.sb.addChannelHandler(this.key, handler); + } + + remove() { + this.sb.removeChannelHandler(this.key); + } + + static getInstance() { + return instance; + } +} + +export { SendBirdChatEvent }; diff --git a/javascript/javascript-basic-syncmanager/src/js/SendBirdConnection.js b/javascript/javascript-basic-syncmanager/src/js/SendBirdConnection.js new file mode 100644 index 00000000..5bda9b1a --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/SendBirdConnection.js @@ -0,0 +1,62 @@ +import { uuid4 } from './utils'; +import SendBird from 'sendbird'; +import { Chat } from './Chat'; + +let instance = null; + +class SendBirdConnection { + constructor() { + if (instance) { + return instance; + } + + this.sb = SendBird.getInstance(); + this.key = uuid4(); + this.channel = null; + this._createConnectionHandler(this.key); + this.chat = Chat.getInstance(); + + this.onReconnectStarted = null; + this.onReconnectSucceeded = null; + this.onReconnectFailed = null; + + instance = this; + } + + _createConnectionHandler(key) { + const handler = new this.sb.ConnectionHandler(); + handler.onReconnectStarted = () => { + if (this.chat && this.chat.main) { + this.chat.main.body.stopSpinner(); + } + if (this.onReconnectStarted) { + this.onReconnectStarted(); + } + }; + handler.onReconnectSucceeded = () => { + if (this.onReconnectSucceeded) { + this.onReconnectSucceeded(); + } + }; + handler.onReconnectFailed = () => { + if (this.onReconnectFailed) { + this.onReconnectFailed(); + } + }; + this.sb.addConnectionHandler(key, handler); + } + + remove() { + this.sb.removeConnectionHandler(this.key); + } + + reconnect() { + this.sb.reconnect(); + } + + static getInstance() { + return new SendBirdConnection(); + } +} + +export { SendBirdConnection }; diff --git a/javascript/javascript-basic-syncmanager/src/js/SendBirdEvent.js b/javascript/javascript-basic-syncmanager/src/js/SendBirdEvent.js new file mode 100644 index 00000000..58c82969 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/SendBirdEvent.js @@ -0,0 +1,47 @@ +import { uuid4 } from './utils'; +import SendBird from 'sendbird'; + +class SendBirdEvent { + constructor() { + this.sb = SendBird.getInstance(); + this.key = uuid4(); + this._createChannelHandler(); + + this.onChannelChanged = null; + this.onUserJoined = null; + this.onUserLeft = null; + this.onChannelHidden = null; + this.onUserEntered = null; + } + + _createChannelHandler() { + const handler = new this.sb.ChannelHandler(); + handler.onChannelChanged = channel => { + if (this.onChannelChanged) { + this.onChannelChanged(channel); + } + }; + handler.onUserJoined = (groupChannel, user) => { + if (this.onUserJoined) { + this.onUserJoined(groupChannel, user); + } + }; + handler.onUserLeft = (groupChannel, user) => { + if (this.onUserLeft) { + this.onUserLeft(groupChannel, user); + } + }; + handler.onChannelHidden = groupChannel => { + if (this.onChannelHidden) { + this.onChannelHidden(groupChannel); + } + }; + this.sb.addChannelHandler(this.key, handler); + } + + remove() { + this.sb.removeChannelHandler(this.key); + } +} + +export { SendBirdEvent }; diff --git a/javascript/javascript-basic-syncmanager/src/js/components/ChatBody.js b/javascript/javascript-basic-syncmanager/src/js/components/ChatBody.js new file mode 100644 index 00000000..04e9d2fc --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/components/ChatBody.js @@ -0,0 +1,266 @@ +import styles from '../../scss/chat-body.scss'; +import { createDivEl, getDataInElement, removeClass, findMessageIndex, mergeFailedWithSuccessful } from '../utils'; +import { Message } from './Message'; +import { SendBirdAction } from '../SendBirdAction'; +import { MESSAGE_REQ_ID } from '../const'; +import SendBirdSyncManager from 'sendbird-syncmanager'; +import { Spinner } from './Spinner'; + +class ChatBody { + constructor(channel) { + this.channel = channel; + this.readReceiptManageList = []; + this.scrollHeight = 0; + this.collection = null; + this.limit = 50; + this.element = createDivEl({ className: styles['chat-body'] }); + this._initElement(); + this.spinnerStarted = false; + } + + _initElement() { + if (this.collection) { + this.collection.remove(); + } + this.collection = new SendBirdSyncManager.MessageCollection(this.channel); + this.collection.limit = this.limit; + + const collectionHandler = new SendBirdSyncManager.MessageCollection.CollectionHandler(); + collectionHandler.onSucceededMessageEvent = this._messageEventHandler.bind(this); + collectionHandler.onFailedMessageEvent = this._messageEventHandler.bind(this); + collectionHandler.onPendingMessageEvent = this._messageEventHandler.bind(this); + collectionHandler.onNewMessage = (event) => { this._onNewMessageEventHandler(event, this.collection) }; + this.collection.setCollectionHandler(collectionHandler); + + this.element.addEventListener('scroll', () => { + if (this.element.scrollTop === 0) { + this.updateCurrentScrollHeight(); + this.collection.fetchSucceededMessages('prev', () => { + this.element.scrollTop = this.element.scrollHeight - this.scrollHeight; + }); + } + + if (this.element.scrollHeight - this.element.scrollTop - this.element.clientHeight === 0) { + const newMessagePop = document.getElementById('new-message-pop'); + if (newMessagePop) newMessagePop.remove(); + } + }); + } + + _onNewMessageEventHandler(event, col) { + const messages = col.messages; + let isOnNewMessage = !(messages.every(message => (message.messageId !== event.messageId))); + + if (isOnNewMessage) { + if (this.element.scrollTop < this.element.scrollHeight - this.element.offsetHeight && !(document.getElementById('new-message-pop'))) { + const newMessagePop = document.createElement('div'); + newMessagePop.setAttribute('id', 'new-message-pop'); + newMessagePop.setAttribute('class', 'new-message-pop'); + + const popText = document.createElement('div'); + popText.setAttribute('class', 'new-message-pop-text'); + popText.innerText = 'check new message'; + newMessagePop.appendChild(popText); + popText.addEventListener('click', () => { + newMessagePop.remove(); + this.scrollToBottom(); + }); + + this.element.appendChild(newMessagePop); + } + } else { + console.log('There is no onNewMessage in collection'); + } + } + + _messageEventHandler(messages, action, reason) { + const keepScrollToBottom = this.element.scrollTop >= this.element.scrollHeight - this.element.offsetHeight; + messages.sort((a, b) => a.createdAt - b.createdAt); + switch (action) { + case 'insert': { + this._mergeMessagesOnInsert(messages); + break; + } + case 'update': { + if (reason === SendBirdSyncManager.MessageCollection.FailedMessageEventActionReason.UPDATE_RESEND_FAILED) { + this._updateMessages(messages, true); + } else { + this._updateMessages(messages); + } + break; + } + case 'remove': { + this._removeMessages(messages); + break; + } + case 'clear': { + this._clearMessages(); + break; + } + default: break; + } + if (keepScrollToBottom) { + this.scrollToBottom(); + } + } + + _mergeMessagesOnInsert(messages) { + const wholeCollectionMessages = mergeFailedWithSuccessful( + this.collection.unsentMessages, + this.collection.succeededMessages + ); + for (let i in messages) { + const message = messages[i]; + const index = findMessageIndex(message, wholeCollectionMessages); + if (index >= 0) { + const messageElements = this.element.querySelectorAll('.chat-message'); + const messageItem = new Message({ channel: this.channel, message, col: this.collection }); + this.element.insertBefore(messageItem.element, messageElements[index]); + if ( + (message.isUserMessage() || message.isFileMessage()) && + SendBirdAction.getInstance().isCurrentUser(message.sender) + ) { + this.readReceiptManage(message); + } + } + } + } + + _updateMessages(messages, transformToManual = false) { + for (let i in messages) { + const message = messages[i]; + const messageItem = new Message({ + channel: this.channel, + message, + isManual: transformToManual, + col: this.collection + }); + const currentItem = this._getItem(message.reqId); + const requestItem = message.reqId ? this._getItem(message.reqId) : null; + if (currentItem || requestItem) { + this.element.replaceChild(messageItem.element, requestItem ? requestItem : currentItem); + } + } + } + + _removeMessages(messages) { + if ( + this.collection.unsentMessages.length > 0 && + messages.length > 0 && + messages[0].messageId === 0 && + !this.spinnerStarted + ) { + const el = this._getItem(messages[0].reqId); + const resendButton = el.firstChild.getElementsByClassName('resend-button'); + if (resendButton && resendButton.length === 0) { + Spinner.start(this.element); + this.spinnerStarted = true; + } + } + for (let i in messages) { + const message = messages[i]; + this.removeMessage(message.reqId); + } + if ( + (this.spinnerStarted && this.collection.unsentMessages.length === 0) || + SendBirdAction.getInstance().getConnectionState() !== 'OPEN' + ) { + this.stopSpinner(); + } + } + + stopSpinner() { + Spinner.remove(); + this.spinnerStarted = false; + } + + _clearMessages() { + while (this.element.firstChild) { + this.element.removeChild(this.element.firstChild); + } + } + + loadPreviousMessages(callback) { + this.collection.fetchSucceededMessages('prev', () => { + this.collection.fetchFailedMessages(() => { + if (callback) callback(); + }); + }); + } + + scrollToBottom() { + this.element.scrollTop = this.element.scrollHeight - this.element.offsetHeight; + } + + updateCurrentScrollHeight() { + this.scrollHeight = this.element.scrollHeight; + } + + repositionScroll(imageOffsetHeight) { + this.element.scrollTop += imageOffsetHeight; + } + + updateReadReceipt() { + this.readReceiptManageList.forEach(message => { + if (message.messageId.toString() !== '0') { + const className = Message.getReadReceiptElementClassName(); + const messageItem = this._getItem(message.reqId); + if (messageItem) { + let readItem = null; + try { + readItem = messageItem.getElementsByClassName(className)[0]; + } catch (e) { + readItem = null; + } + const latestCount = SendBirdAction.getInstance().getReadReceipt(this.channel, message); + if (readItem && latestCount.toString() !== readItem.textContent.toString()) { + readItem.innerHTML = latestCount; + if (latestCount.toString() === '0') { + removeClass(readItem, className); + } + } + } + } + }); + } + + readReceiptManage(message) { + for (let i = 0; i < this.readReceiptManageList.length; i++) { + if (message.reqId) { + if (this.readReceiptManageList[i].reqId === message.reqId) { + this.readReceiptManageList.splice(i, 1); + break; + } + } else { + if (this.readReceiptManageList[i].messageId === message.messageId) { + this.readReceiptManageList.splice(i, 1); + break; + } + } + } + this.readReceiptManageList.push(message); + this.updateReadReceipt(); + } + + _getItem(reqId) { + const items = this.element.childNodes; + // We go in reverse order to prevent situations that + // pending-message remove requests accidentally delete succeeded messages + for (let i = items.length - 1; i >= 0; i--) { + const elementId = getDataInElement(items[i], MESSAGE_REQ_ID); + if (elementId === reqId.toString()) { + return items[i]; + } + } + return null; + } + + removeMessage(reqId) { + const removeElement = this._getItem(reqId); + if (removeElement) { + this.element.removeChild(removeElement); + } + } +} + +export { ChatBody }; diff --git a/javascript/javascript-basic-syncmanager/src/js/components/ChatInput.js b/javascript/javascript-basic-syncmanager/src/js/components/ChatInput.js new file mode 100644 index 00000000..a7ab8e4e --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/components/ChatInput.js @@ -0,0 +1,119 @@ +import styles from '../../scss/chat-input.scss'; +import { createDivEl, protectFromXSS } from '../utils'; +import { DISPLAY_BLOCK, DISPLAY_NONE, FILE_ID, KEY_ENTER } from '../const'; +import { SendBirdAction } from '../SendBirdAction'; +import { Chat } from '../Chat'; + +class ChatInput { + constructor(channel) { + this.channel = channel; + this.input = null; + this.typing = null; + this.element = this._createElement(channel); + } + + _createElement(channel) { + const sendbirdAction = SendBirdAction.getInstance(); + const chat = Chat.getInstance(); + const root = createDivEl({ className: styles['chat-input'] }); + + this.typing = createDivEl({ className: styles['typing-field'] }); + root.appendChild(this.typing); + + const file = document.createElement('label'); + file.className = styles['input-file']; + file.for = FILE_ID; + file.addEventListener('click', () => { + sendbirdAction.markAsRead(this.channel); + }); + + const fileInput = document.createElement('input'); + fileInput.type = 'file'; + fileInput.id = FILE_ID; + fileInput.style.display = DISPLAY_NONE; + fileInput.addEventListener('change', () => { + const sendFile = fileInput.files[0]; + if (sendFile) { + const previewMessage = SendBirdAction.getInstance().sendFileMessage({ + channel: this.channel, + file: sendFile, + thumbnailSizes: [{ maxWidth: 240, maxHeight: 240 }, { maxWidth: 320, maxHeight: 320 }], + handler: (message, error) => { + if (!error) { + chat.main.body.collection.appendMessage(message); + } + chat.main.body.scrollToBottom(); + } + }); + previewMessage.createdAt = new Date().getTime(); + chat.main.body.collection.appendMessage(previewMessage); + } + }); + + file.appendChild(fileInput); + root.appendChild(file); + + const inputText = createDivEl({ className: styles['input-text'] }); + + this.input = document.createElement('textarea'); + this.input.className = styles['input-text-area']; + this.input.placeholder = 'Write a chat...'; + this.input.addEventListener('click', () => { + sendbirdAction.markAsRead(this.channel); + }); + this.input.addEventListener('keypress', e => { + if (e.keyCode === KEY_ENTER) { + if (!e.shiftKey) { + e.preventDefault(); + const message = this.input.value; + this.input.value = ''; + if (message) { + const previewMessage = SendBirdAction.getInstance().sendUserMessage({ + channel: this.channel, + message, + handler: (message, error) => { + chat.main.body.collection.handleSendMessageResponse(error, message); + chat.main.body.scrollToBottom(); + } + }); + chat.main.body.collection.appendMessage(previewMessage); + channel.endTyping(); + } + } else { + channel.startTyping(); + } + } else { + channel.startTyping(); + } + }); + this.input.addEventListener('focusin', () => { + inputText.style.border = '1px solid #2C2D30'; + }); + this.input.addEventListener('focusout', () => { + inputText.style.border = ''; + }); + + inputText.appendChild(this.input); + root.appendChild(inputText); + return root; + } + + updateTyping(memberList) { + let nicknames = ''; + if (memberList.length === 1) { + nicknames = `${protectFromXSS(memberList[0].nickname)} is`; + } else if (memberList.length === 2) { + nicknames = `${memberList + .map(member => { + return protectFromXSS(member.nickname); + }) + .join(', ')} are`; + } else if (memberList.length !== 0) { + nicknames = 'Several are'; + } + this.typing.style.display = nicknames ? DISPLAY_BLOCK : DISPLAY_NONE; + this.typing.innerHTML = `${nicknames} typing...`; + } +} + +export { ChatInput }; diff --git a/javascript/javascript-basic-syncmanager/src/js/components/ChatMain.js b/javascript/javascript-basic-syncmanager/src/js/components/ChatMain.js new file mode 100644 index 00000000..dd8826bb --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/components/ChatMain.js @@ -0,0 +1,57 @@ +import styles from '../../scss/chat-main.scss'; +import { ChatBody } from './ChatBody'; +import { ChatInput } from './ChatInput'; +import { Chat } from '../Chat'; +import { createDivEl } from '../utils'; +import { ChatMenu } from './ChatMenu'; +import { SendBirdAction } from '../SendBirdAction'; + +class ChatMain { + constructor(channel) { + this.channel = channel; + this.body = null; + this.input = null; + this.menu = null; + this._create(); + } + + _create() { + const root = createDivEl({ className: styles['chat-main-root'] }); + + const main = createDivEl({ className: styles['chat-main'] }); + root.appendChild(main); + + this.body = new ChatBody(this.channel); + main.appendChild(this.body.element); + + this.input = new ChatInput(this.channel); + main.appendChild(this.input.element); + + this.menu = new ChatMenu(this.channel); + root.appendChild(this.menu.element); + + Chat.getInstance().element.appendChild(root); + } + + updateTyping(memberList) { + this.input.updateTyping(memberList); + } + + repositionScroll(height) { + this.body.repositionScroll(height); + } + + updateBlockedList(user, isBlock) { + this.menu.updateBlockedList(user, isBlock); + } + + loadInitialMessages() { + const sendbirdAction = SendBirdAction.getInstance(); + this.body.loadPreviousMessages(() => { + sendbirdAction.markAsRead(this.channel); + this.body.scrollToBottom(); + }); + } +} + +export { ChatMain }; diff --git a/javascript/javascript-basic-syncmanager/src/js/components/ChatMenu.js b/javascript/javascript-basic-syncmanager/src/js/components/ChatMenu.js new file mode 100644 index 00000000..0ad4e845 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/components/ChatMenu.js @@ -0,0 +1,155 @@ +import styles from '../../scss/chat-menu.scss'; +import { appendToFirst, errorAlert, createDivEl } from '../utils'; +import { DISPLAY_FLEX, DISPLAY_NONE } from '../const'; +import { Spinner } from './Spinner'; +import { ChatUserItem } from './ChatUserItem'; +import { SendBirdAction } from '../SendBirdAction'; + +const Type = { + PARTICIPANTS: 'PARTICIPANTS', + MEMBERS: 'MEMBERS', + BLOCKED: 'BLOCKED' +}; + +class ChatMenu { + constructor(channel) { + this.channel = channel; + this.element = createDivEl({ className: styles['chat-menu-root'] }); + this.listElement = null; + this.type = null; + this._createListElement(); + this._createElement(); + } + + _createListElement() { + this.listElement = createDivEl({ className: styles['menu-list'] }); + + const title = createDivEl({ className: styles['list-title'] }); + title.addEventListener('click', () => { + this.type = null; + this.list.innerHTML = ''; + this.listElement.style.display = DISPLAY_NONE; + }); + this.listElement.appendChild(title); + const backBtn = createDivEl({ className: styles['list-back'] }); + title.appendChild(backBtn); + this.titleText = createDivEl({ className: styles['list-text'] }); + title.appendChild(this.titleText); + + this.list = createDivEl({ className: styles['list-body'] }); + this.list.addEventListener('scroll', () => { + if (this.type === Type.BLOCKED) { + this._getBlockedList(this.type); + } + }); + this.listElement.appendChild(this.list); + + this.element.appendChild(this.listElement); + } + + _createElement() { + const usersItem = createDivEl({ className: styles['menu-item'] }); + const users = createDivEl({ + className: styles['menu-users'], + content: Type.MEMBERS + }); + usersItem.appendChild(users); + const arrowUser = createDivEl({ className: styles['menu-arrow'] }); + usersItem.appendChild(arrowUser); + usersItem.addEventListener('click', () => { + this._renderList(users.textContent); + }); + this.element.appendChild(usersItem); + + const blockedItem = createDivEl({ className: styles['menu-item'] }); + const blocked = createDivEl({ className: styles['menu-blocked'], content: Type.BLOCKED }); + blockedItem.appendChild(blocked); + const arrowBlocked = createDivEl({ className: styles['menu-arrow'] }); + blockedItem.appendChild(arrowBlocked); + blockedItem.addEventListener('click', () => { + this._renderList(blocked.textContent); + }); + this.element.appendChild(blockedItem); + } + + _renderList(listTitle) { + switch (listTitle) { + case Type.MEMBERS: + this.type = Type.MEMBERS; + this._getMemberList(listTitle); + break; + case Type.BLOCKED: + this.type = Type.BLOCKED; + this._getBlockedList(listTitle, true); + break; + default: + this.titleText.innerHTML = ''; + break; + } + } + + _getMemberList(listTitle) { + if (this.channel.isGroupChannel()) { + Spinner.start(this.listElement); + this.list.innerHTML = ''; + this.titleText.innerHTML = listTitle; + this.listElement.style.display = DISPLAY_FLEX; + this.channel.members.forEach(user => { + const memberItem = new ChatUserItem({ user, hasEvent: false }); + this.list.appendChild(memberItem.element); + }); + Spinner.remove(); + } + } + + _getBlockedList(listTitle, isInit = false) { + Spinner.start(this.listElement); + if (isInit) { + this.list.innerHTML = ''; + this.titleText.innerHTML = listTitle; + this.listElement.style.display = DISPLAY_FLEX; + } + SendBirdAction.getInstance() + .getBlockedList(isInit) + .then(blockedList => { + blockedList.forEach(user => { + const blockedItem = new ChatUserItem({ user, hasEvent: true }); + this.list.appendChild(blockedItem.element); + }); + Spinner.remove(); + }) + .catch(error => { + errorAlert(error.message); + }); + } + + updateBlockedList(user, isBlock) { + if (this.list) { + if (isBlock) { + const blockedItem = new ChatUserItem({ user, hasEvent: true }); + appendToFirst(this.list, blockedItem.element); + } else { + const items = this.list.childNodes; + for (let i = 0; i < items.length; i++) { + if (items[0].id === user.userId) { + this.list.removeChild(items[0]); + break; + } + } + } + } + } + + updateMenu(channel) { + if (this.type === Type.MEMBERS) { + this.channel = channel; + this._getMemberList(this.type); + } + } + + static get Type() { + return Type; + } +} + +export { ChatMenu }; diff --git a/javascript/javascript-basic-syncmanager/src/js/components/ChatTopMenu.js b/javascript/javascript-basic-syncmanager/src/js/components/ChatTopMenu.js new file mode 100644 index 00000000..9c81f892 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/components/ChatTopMenu.js @@ -0,0 +1,73 @@ +import styles from '../../scss/chat-top-menu.scss'; +import { createDivEl, errorAlert, protectFromXSS } from '../utils'; +import { Chat } from '../Chat'; +import { UserList } from './UserList'; +import { SendBirdAction } from '../SendBirdAction'; + +class ChatTopMenu { + constructor(channel) { + this.channel = channel; + this.element = this._createElement(channel); + } + + get chatTitle() { + return this.channel.members + .map(member => { + return protectFromXSS(member.nickname); + }) + .join(', '); + } + + _createElement(channel) { + const root = createDivEl({ className: styles['chat-top'] }); + + this.title = createDivEl({ + className: [styles['chat-title'], styles['is-group']], + content: this.chatTitle + }); + root.appendChild(this.title); + + const button = createDivEl({ className: styles['chat-button'] }); + const invite = createDivEl({ className: styles['button-invite'] }); + invite.addEventListener('click', () => { + UserList.getInstance().render(true); + }); + button.appendChild(invite); + const hide = createDivEl({ className: styles['button-hide'] }); + hide.addEventListener('click', () => { + SendBirdAction.getInstance() + .hide(channel.url) + .then(() => { + // ChatLeftMenu.getInstance().removeGroupChannelItem(this.channel.url); + Chat.getInstance().renderEmptyElement(); + }) + .catch(error => { + errorAlert(error.message); + }); + }); + button.appendChild(hide); + + const leave = createDivEl({ className: styles['button-leave'] }); + leave.addEventListener('click', () => { + SendBirdAction.getInstance() + .leave(channel.url) + .then(() => { + // ChatLeftMenu.getInstance().removeGroupChannelItem(this.channel.url); + Chat.getInstance().renderEmptyElement(); + }) + .catch(error => { + errorAlert(error.message); + }); + }); + button.appendChild(leave); + root.appendChild(button); + return root; + } + + updateTitle(channel) { + this.channel = channel; + this.title.innerHTML = this.chatTitle; + } +} + +export { ChatTopMenu }; diff --git a/javascript/javascript-basic-syncmanager/src/js/components/ChatUserItem.js b/javascript/javascript-basic-syncmanager/src/js/components/ChatUserItem.js new file mode 100644 index 00000000..fcc51d66 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/components/ChatUserItem.js @@ -0,0 +1,49 @@ +import styles from '../../scss/chat-user-item.scss'; +import { createDivEl, protectFromXSS } from '../utils'; +import { COLOR_RED } from '../const'; +import { UserBlockModal } from './UserBlockModal'; +import { SendBirdAction } from '../SendBirdAction'; + +class ChatUserItem { + constructor({ user, hasEvent }) { + this.user = user; + this.hasEvent = hasEvent; + this.element = null; + this._create(); + } + + _create() { + this.element = createDivEl({ className: styles['chat-user-item'], id: this.user.userId }); + if (this.hasEvent) { + this.element.addEventListener('mouseover', () => { + this._hoverOnUser(this.user.nickname, true); + }); + this.element.addEventListener('mouseleave', () => { + this._hoverOnUser(this.user.nickname, false); + }); + this.element.addEventListener('click', () => { + const userBlockModal = new UserBlockModal({ user: this.user, isBlock: false }); + userBlockModal.render(); + }); + } + + const image = createDivEl({ className: styles['user-image'], background: protectFromXSS(this.user.profileUrl) }); + this.element.appendChild(image); + + this.nickname = createDivEl({ + className: SendBirdAction.getInstance().isCurrentUser(this.user) + ? [styles['user-nickname'], styles['is-user']] + : styles['user-nickname'], + content: protectFromXSS(this.user.nickname) + }); + this.element.appendChild(this.nickname); + } + + _hoverOnUser(nickname, hover) { + this.nickname.innerHTML = hover ? 'UNBLOCK' : protectFromXSS(nickname); + this.nickname.style.color = hover ? COLOR_RED : ''; + this.nickname.style.opacity = hover ? '1' : ''; + } +} + +export { ChatUserItem }; diff --git a/javascript/javascript-basic-syncmanager/src/js/components/LeftListItem.js b/javascript/javascript-basic-syncmanager/src/js/components/LeftListItem.js new file mode 100644 index 00000000..43d3dbb4 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/components/LeftListItem.js @@ -0,0 +1,138 @@ +import styles from '../../scss/list-item.scss'; +import { + addClass, + createDivEl, + getDataInElement, + protectFromXSS, + removeClass, + setDataInElement, + timestampFromNow +} from '../utils'; +import { ChatLeftMenu } from '../ChatLeftMenu'; + +const KEY_MESSAGE_LAST_TIME = 'origin'; + +class LeftListItem { + constructor({ channel, handler }) { + this.channel = channel; + this.element = this._createElement(handler); + } + + get channelUrl() { + return this.channel.url; + } + + get title() { + return this.channel.members + .map(member => { + return protectFromXSS(member.nickname); + }) + .join(', '); + } + + get lastMessagetime() { + if (!this.channel.lastMessage) { + return 0; + } else { + return this.channel.lastMessage.createdAt; + } + } + + get lastMessageTimeText() { + if (!this.channel.lastMessage) { + return 0; + } else { + return LeftListItem.getTimeFromNow(this.channel.lastMessage.createdAt); + } + } + + get lastMessageText() { + if (!this.channel.lastMessage) { + return ''; + } else { + return this.channel.lastMessage.isFileMessage() + ? protectFromXSS(this.channel.lastMessage.name) + : protectFromXSS(this.channel.lastMessage.message); + } + } + + get memberCount() { + return this.channel.memberCount; + } + + get unreadMessageCount() { + const count = this.channel.unreadMessageCount > 9 ? '+9' : this.channel.unreadMessageCount.toString(); + return count; + } + + _createElement(handler) { + const item = createDivEl({ className: styles['list-item'], id: this.channelUrl }); + const itemTop = createDivEl({ className: styles['item-top'] }); + const itemTopCount = createDivEl({ className: styles['item-count'], content: this.memberCount }); + const itemTopTitle = createDivEl({ className: styles['item-title'], content: this.title }); + itemTop.appendChild(itemTopCount); + itemTop.appendChild(itemTopTitle); + item.appendChild(itemTop); + + const itemBottom = createDivEl({ className: styles['item-bottom'] }); + + const itemBottomMessage = createDivEl({ className: styles['item-message'] }); + const itemBottomMessageText = createDivEl({ + className: styles['item-message-text'], + content: this.lastMessageText + }); + itemBottomMessage.appendChild(itemBottomMessageText); + const itemBottomMessageUnread = createDivEl({ + className: [styles['item-message-unread'], styles.active], + content: this.unreadMessageCount + }); + itemBottomMessage.appendChild(itemBottomMessageUnread); + + const itemBottomTime = createDivEl({ className: styles['item-time'], content: this.lastMessageTimeText }); + setDataInElement(itemBottomTime, KEY_MESSAGE_LAST_TIME, this.lastMessagetime); + itemBottom.appendChild(itemBottomMessage); + itemBottom.appendChild(itemBottomTime); + item.appendChild(itemBottom); + + item.addEventListener('click', () => { + if (handler) handler(); + }); + return item; + } + + static updateUnreadCount() { + const items = ChatLeftMenu.getInstance().groupChannelList.getElementsByClassName(styles['item-message-unread']); + if (items && items.length > 0) { + Array.prototype.slice.call(items).forEach(targetItemEl => { + const originTs = targetItemEl.textContent; + if (originTs === '0') { + removeClass(targetItemEl, styles.active); + } else { + addClass(targetItemEl, styles.active); + } + }); + } + } + + static updateLastMessageTime() { + const items = ChatLeftMenu.getInstance().groupChannelList.getElementsByClassName(styles['item-time']); + if (items && items.length > 0) { + Array.prototype.slice.call(items).forEach(targetItemEl => { + const originTs = parseInt(getDataInElement(targetItemEl, KEY_MESSAGE_LAST_TIME)); + if (originTs) { + targetItemEl.innerHTML = LeftListItem.getTimeFromNow(originTs); + } + }); + } + } + + static getTimeFromNow(timestamp) { + return timestampFromNow(timestamp); + } + + static getItemRootClassName() { + return styles['list-item']; + } +} + +export { LeftListItem }; diff --git a/javascript/javascript-basic-syncmanager/src/js/components/List.js b/javascript/javascript-basic-syncmanager/src/js/components/List.js new file mode 100644 index 00000000..2350f8ec --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/components/List.js @@ -0,0 +1,80 @@ +import styles from '../../scss/list.scss'; +import { createDivEl, isScrollBottom } from '../utils'; + +let instance = null; + +class List { + constructor(title, createSearchBox = false) { + if (instance) { + return instance; + } + this.createSearchBox = createSearchBox; + this.element = this._create(title); + this.scrollEventHandler = null; + this.closeEventHandler = null; + this.searchKeyword = ''; + } + + _create(title) { + const root = createDivEl({ className: styles['list-root'] }); + + const listBody = createDivEl({ className: styles['list-body'] }); + root.appendChild(listBody); + + const listTop = createDivEl({ className: styles['list-top'] }); + listBody.appendChild(listTop); + + const listTopTitle = createDivEl({ className: styles['list-title'], content: title }); + listTop.appendChild(listTopTitle); + const listTopButton = createDivEl({ className: styles['list-button'] }); + listTop.appendChild(listTopButton); + const listTopButtonExit = createDivEl({ className: styles['button-exit'] }); + listTopButton.appendChild(listTopButtonExit); + listTopButtonExit.addEventListener('click', () => { + this.searchKeyword = ''; + const listContent = document.querySelector(`.${styles['list-content']}`); + if (this.closeEventHandler) { + this.closeEventHandler(); + } + listContent.innerHTML = ''; + root.parentElement.removeChild(this.element); + }); + this.buttonRootElement = listTopButton; + + const hr = createDivEl({ className: styles['list-hr'] }); + listBody.appendChild(hr); + + const listContent = createDivEl({ className: styles['list-content'] }); + listBody.appendChild(listContent); + listContent.addEventListener('scroll', () => { + if (isScrollBottom(listContent)) { + if (this.scrollEventHandler) { + this.scrollEventHandler(false, this.searchKeyword); + } + } + }); + + return root; + } + + close() { + const btnExit = document.querySelector(`.${styles['button-exit']}`); + if (btnExit) { + document.querySelector(`.${styles['button-exit']}`).click(); + } + } + + getRootElement() { + return document.querySelector(`.${styles['list-root']}`); + } + + getRootClassName() { + return styles['list-root']; + } + + getContentElement() { + return document.querySelector(`.${styles['list-content']}`); + } +} + +export { List }; diff --git a/javascript/javascript-basic-syncmanager/src/js/components/Message.js b/javascript/javascript-basic-syncmanager/src/js/components/Message.js new file mode 100644 index 00000000..7f9ea5ce --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/components/Message.js @@ -0,0 +1,245 @@ +import styles from '../../scss/message.scss'; +import { createDivEl, isImage, protectFromXSS, setDataInElement, timestampToTime } from '../utils'; +import { SendBirdAction } from '../SendBirdAction'; +import { COLOR_RED, MESSAGE_REQ_ID } from '../const'; +import { MessageDeleteModal } from './MessageDeleteModal'; +import { UserBlockModal } from './UserBlockModal'; +import { Chat } from '../Chat'; + +class Message { + constructor({ channel, message, isManual = false, col = null }) { + this.channel = channel; + this.message = message; + this.isFailed = message.messageId === 0 && message.requestState === 'failed'; + this.isManual = this.isFailed ? isManual : false; + this.element = this._createElement(); + if (col) { + this.col = col; + } + } + + _createElement() { + if (this.message.isUserMessage()) { + return this._createUserElement(); + } else if (this.message.isFileMessage()) { + return this._createFileElement(); + } else if (this.message.isAdminMessage()) { + return this._createAdminElement(); + } else { + // console.error('Message is invalid data.'); + return null; + } + } + + _hoverOnNickname(nickname, hover) { + if (!SendBirdAction.getInstance().isCurrentUser(this.message.sender)) { + nickname.innerHTML = hover ? 'BLOCK ' : `${protectFromXSS(this.message.sender.nickname)} : `; + nickname.style.color = hover ? COLOR_RED : ''; + nickname.style.opacity = hover ? '1' : ''; + } + } + + _hoverOnTime(time, hover) { + if (SendBirdAction.getInstance().isCurrentUser(this.message.sender)) { + time.innerHTML = hover ? 'DELETE' : timestampToTime(this.message.createdAt); + time.style.color = hover ? COLOR_RED : ''; + time.style.opacity = hover ? '1' : ''; + time.style.fontWeight = hover ? '600' : ''; + } + } + + _createUserElement() { + const sendbirdAction = SendBirdAction.getInstance(); + const isCurrentUser = sendbirdAction.isCurrentUser(this.message.sender); + let root; + if (this.isFailed && !this.isManual) { + root = createDivEl({ + className: [styles['chat-message'], styles['is-failed']], + id: this.message.reqId + }); + } else { + root = createDivEl({ + className: styles['chat-message'], + id: this.message.reqId + }); + } + setDataInElement(root, MESSAGE_REQ_ID, this.message.reqId); + + const messageContent = createDivEl({ className: styles['message-content'] }); + const nickname = createDivEl({ + className: isCurrentUser ? [styles['message-nickname'], styles['is-user']] : styles['message-nickname'], + content: `${protectFromXSS(this.message.sender.nickname)} : ` + }); + nickname.addEventListener('mouseover', () => { + this._hoverOnNickname(nickname, true); + }); + nickname.addEventListener('mouseleave', () => { + this._hoverOnNickname(nickname, false); + }); + nickname.addEventListener('click', () => { + if (!isCurrentUser) { + const userBlockModal = new UserBlockModal({ user: this.message.sender, isBlock: true }); + userBlockModal.render(); + } + }); + messageContent.appendChild(nickname); + + const msg = createDivEl({ className: styles['message-content'], content: protectFromXSS(this.message.message) }); + messageContent.appendChild(msg); + + if (this.isFailed && this.isManual) { + const resendButton = createDivEl({ + className: styles['resend-button'], + content: 'RESEND' + }); + resendButton.addEventListener('click', () => { + this._resendUserMessage(); + }); + messageContent.appendChild(resendButton); + } + if (this.isFailed) { + const deleteButton = createDivEl({ + className: styles['delete-button'], + content: 'DELETE' + }); + deleteButton.addEventListener('click', () => { + if (isCurrentUser) { + const messageDeleteModal = new MessageDeleteModal({ + channel: this.channel, + message: this.message, + col: this.col + }); + messageDeleteModal.render(); + } + }); + messageContent.appendChild(deleteButton); + } + if (!this.isFailed) { + const time = createDivEl({ + className: isCurrentUser ? [styles.time, styles['is-user']] : styles.time, + content: timestampToTime(this.message.createdAt) + }); + time.addEventListener('mouseover', () => { + this._hoverOnTime(time, true); + }); + time.addEventListener('mouseleave', () => { + this._hoverOnTime(time, false); + }); + time.addEventListener('click', () => { + if (isCurrentUser) { + const messageDeleteModal = new MessageDeleteModal({ + channel: this.channel, + message: this.message + }); + messageDeleteModal.render(); + } + }); + messageContent.appendChild(time); + + const count = sendbirdAction.getReadReceipt(this.channel, this.message); + const read = createDivEl({ + className: count ? [styles.read, styles.active] : styles.read, + content: count + }); + messageContent.appendChild(read); + } + + root.appendChild(messageContent); + return root; + } + + _resendUserMessage() { + this.channel.resendUserMessage(this.message, (message, err) => { + this.col.handleSendMessageResponse(err, message); + }); + } + + _createFileElement() { + const sendbirdAction = SendBirdAction.getInstance(); + const root = createDivEl({ className: styles['chat-message'], id: this.message.messageId }); + setDataInElement(root, MESSAGE_REQ_ID, this.message.reqId); + + const messageContent = createDivEl({ className: styles['message-content'] }); + const nickname = createDivEl({ + className: sendbirdAction.isCurrentUser(this.message.sender) + ? [styles['message-nickname'], styles['is-user']] + : styles['message-nickname'], + content: `${protectFromXSS(this.message.sender.nickname)} : ` + }); + messageContent.appendChild(nickname); + + const msg = createDivEl({ + className: [styles['message-content'], styles['is-file']], + content: protectFromXSS(this.message.name) + }); + msg.addEventListener('click', () => { + window.open(this.message.url); + }); + messageContent.appendChild(msg); + + const time = createDivEl({ className: styles.time, content: timestampToTime(this.message.createdAt) }); + time.addEventListener('mouseover', () => { + this._hoverOnTime(time, true); + }); + time.addEventListener('mouseleave', () => { + this._hoverOnTime(time, false); + }); + time.addEventListener('click', () => { + const messageDeleteModal = new MessageDeleteModal({ + channel: this.channel, + message: this.message + }); + messageDeleteModal.render(); + }); + messageContent.appendChild(time); + + if (this.channel.isGroupChannel()) { + const count = sendbirdAction.getReadReceipt(this.channel, this.message); + const read = createDivEl({ + className: count ? [styles.read, styles.active] : styles.read, + content: count + }); + messageContent.appendChild(read); + } + + root.appendChild(messageContent); + + if (this.message.isFileMessage() && this.message.messageId) { + const fileContent = createDivEl({ className: styles['file-content'] }); + fileContent.addEventListener('click', () => { + window.open(this.message.url); + }); + if (this.message.thumbnails.length > 0 || isImage(this.message.type)) { + const fileRender = document.createElement('img'); + fileRender.className = styles['file-render']; + + if (isImage(this.message.type)) { + fileRender.src = protectFromXSS(this.message.url); + } else if (this.message.thumbnails.length > 0) { + fileRender.src = protectFromXSS(this.message.thumbnails[0].url); + } + + fileRender.onload = () => { + Chat.getInstance().main.repositionScroll(fileRender.offsetHeight); + }; + fileContent.appendChild(fileRender); + } + root.appendChild(fileContent); + } + + return root; + } + + _createAdminElement() { + const root = createDivEl({ className: styles['chat-message'], id: this.message.messageId }); + const msg = createDivEl({ className: styles['message-admin'], content: protectFromXSS(this.message.message) }); + root.appendChild(msg); + return root; + } + + static getReadReceiptElementClassName() { + return styles.active; + } +} + +export { Message }; diff --git a/javascript/javascript-basic-syncmanager/src/js/components/MessageDeleteModal.js b/javascript/javascript-basic-syncmanager/src/js/components/MessageDeleteModal.js new file mode 100644 index 00000000..ffa1e6ab --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/components/MessageDeleteModal.js @@ -0,0 +1,42 @@ +import styles from '../../scss/message-delete-modal.scss'; +import { createDivEl, errorAlert, protectFromXSS } from '../utils'; +import { SendBirdAction } from '../SendBirdAction'; +import { Spinner } from './Spinner'; +import { Modal } from './Modal'; + +const title = 'Delete Message'; +const description = 'Are you Sure? Do you want to delete message?'; +const submitText = 'DELETE'; + +class MessageDeleteModal extends Modal { + constructor({ channel, message, col }) { + super({ title, description, submitText }); + this.channel = channel; + this.message = message; + this.col = col; + this._createElement(); + + this.submitHandler = () => { + SendBirdAction.getInstance() + .deleteMessage({ channel: this.channel, message: this.message, col: this.col }) + .then(() => { + Spinner.remove(); + this.close(); + }) + .catch(error => { + Spinner.remove(); + errorAlert(error.message); + }); + }; + } + + _createElement() { + const content = createDivEl({ + className: styles['modal-message'], + content: this.message.isFileMessage() ? protectFromXSS(this.message.name) : protectFromXSS(this.message.message) + }); + this.contentElement.appendChild(content); + } +} + +export { MessageDeleteModal }; diff --git a/javascript/javascript-basic-syncmanager/src/js/components/Modal.js b/javascript/javascript-basic-syncmanager/src/js/components/Modal.js new file mode 100644 index 00000000..d90ea634 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/components/Modal.js @@ -0,0 +1,62 @@ +import styles from '../../scss/modal.scss'; +import { createDivEl } from '../utils'; +import { Spinner } from './Spinner'; + +class Modal { + constructor({ title, description, submitText }) { + this.contentElement = null; + this.cancelHandler = null; + this.submitHandler = null; + this.element = this._create({ title, description, submitText }); + } + + _create({ title, description, submitText }) { + const root = createDivEl({ className: styles['modal-root'] }); + const modal = createDivEl({ className: styles['modal-body'] }); + root.appendChild(modal); + + const titleText = createDivEl({ className: styles['modal-title'], content: title }); + modal.appendChild(titleText); + + const desc = createDivEl({ className: styles['modal-desc'], content: description }); + modal.appendChild(desc); + + this.contentElement = createDivEl({ className: styles['modal-content'] }); + modal.appendChild(this.contentElement); + + const bottom = createDivEl({ className: styles['modal-bottom'] }); + modal.appendChild(bottom); + const cancel = createDivEl({ className: styles['modal-cancel'], content: 'CANCEL' }); + cancel.addEventListener('click', () => { + if (this.cancelHandler) { + this.cancelHandler(); + } + this.close(); + }); + bottom.appendChild(cancel); + const submit = createDivEl({ className: styles['modal-submit'], content: submitText }); + submit.addEventListener('click', () => { + Spinner.start(modal); + if (this.submitHandler) { + this.submitHandler(); + } + }); + bottom.appendChild(submit); + + return root; + } + + close() { + if (document.body.contains(this.element)) { + document.body.removeChild(this.element); + } + } + + render() { + if (!document.body.querySelector(`.${styles['modal-root']}`)) { + document.body.appendChild(this.element); + } + } +} + +export { Modal }; diff --git a/javascript/javascript-basic-syncmanager/src/js/components/Spinner.js b/javascript/javascript-basic-syncmanager/src/js/components/Spinner.js new file mode 100644 index 00000000..b7d83297 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/components/Spinner.js @@ -0,0 +1,42 @@ +import styles from '../../scss/spinner.scss'; +import { createDivEl } from '../utils'; + +let instance = null; + +class Spinner { + constructor() { + if (instance) { + return instance; + } + this.element = this._createSpinner(); + instance = this; + } + + _createSpinner() { + const item = createDivEl({ className: styles['sb-spinner'] }); + const bubble = createDivEl({ className: styles['sb-spinner-bubble'] }); + item.appendChild(bubble); + return item; + } + + static start(target) { + const spinnerEl = Spinner.getInstance().element; + if (!target.contains(spinnerEl)) { + target.appendChild(spinnerEl); + } + } + + static remove() { + const spinnerEl = Spinner.getInstance().element; + const targetEl = spinnerEl.parentElement; + if (targetEl && targetEl.contains(spinnerEl)) { + spinnerEl.parentElement.removeChild(spinnerEl); + } + } + + static getInstance() { + return new Spinner(); + } +} + +export { Spinner }; diff --git a/javascript/javascript-basic-syncmanager/src/js/components/Toast.js b/javascript/javascript-basic-syncmanager/src/js/components/Toast.js new file mode 100644 index 00000000..c215c251 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/components/Toast.js @@ -0,0 +1,49 @@ +import styles from '../../scss/toast.scss'; +import { createDivEl } from '../utils'; + +let instance = null; + +class Toast { + constructor(message) { + if (instance) { + const messageEl = instance.element.getElementsByClassName('sb-toast-message')[0]; + if (messageEl) { + if (!message) { + message = messageEl.innerHTML; + } + messageEl.innerHTML = message; + } + return instance; + } + this.element = this._createToast(message); + instance = this; + } + + _createToast(text) { + const item = createDivEl({ className: styles['sb-toast'] }); + const message = createDivEl({ className: styles['sb-toast-message'] }); + message.innerHTML = text; + item.appendChild(message); + return item; + } + + static start(target, message) { + const toast = new Toast(message); + const toastEl = toast.element; + if (!target.contains(toastEl)) { + target.appendChild(toastEl); + } + } + + static remove() { + const toastEl = instance ? instance.element : null; + if (toastEl) { + const targetEl = toastEl.parentElement; + if (targetEl && targetEl.contains(toastEl)) { + toastEl.parentElement.removeChild(toastEl); + } + } + } +} + +export { Toast }; diff --git a/javascript/javascript-basic-syncmanager/src/js/components/UserBlockModal.js b/javascript/javascript-basic-syncmanager/src/js/components/UserBlockModal.js new file mode 100644 index 00000000..85f9d1c7 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/components/UserBlockModal.js @@ -0,0 +1,53 @@ +import styles from '../../scss/user-block-modal.scss'; +import { createDivEl, errorAlert, protectFromXSS } from '../utils'; +import { SendBirdAction } from '../SendBirdAction'; +import { Spinner } from './Spinner'; +import { Modal } from './Modal'; +import { Chat } from '../Chat'; + +const blockTitle = 'Block User'; +const blockDescription = 'Are you Sure? Do you want to block this user?'; +const blockSubmitText = 'BLOCK'; + +const unblockTitle = 'Unblock User'; +const unblockDescription = 'Are you Sure? Do you want to unblock this user?'; +const unblockSubmitText = 'UNBLOCK'; + +class UserBlockModal extends Modal { + constructor({ user, isBlock = true }) { + isBlock + ? super({ title: blockTitle, description: blockDescription, submitText: blockSubmitText }) + : super({ title: unblockTitle, description: unblockDescription, submitText: unblockSubmitText }); + this.isBlock = isBlock; + this.user = user; + this._createElement(); + + this.submitHandler = () => { + SendBirdAction.getInstance() + .blockUser(this.user, this.isBlock) + .then(() => { + Chat.getInstance().main.updateBlockedList(this.user, this.isBlock); + Spinner.remove(); + this.close(); + }) + .catch(error => { + Spinner.remove(); + errorAlert(error.message); + }); + }; + } + + _createElement() { + const content = createDivEl({ className: styles['modal-user'] }); + + const image = createDivEl({ className: styles['user-profile'], background: protectFromXSS(this.user.profileUrl) }); + content.appendChild(image); + + const nickname = createDivEl({ className: styles['user-nickname'], content: protectFromXSS(this.user.nickname) }); + content.appendChild(nickname); + + this.contentElement.appendChild(content); + } +} + +export { UserBlockModal }; diff --git a/javascript/javascript-basic-syncmanager/src/js/components/UserItem.js b/javascript/javascript-basic-syncmanager/src/js/components/UserItem.js new file mode 100644 index 00000000..799ec0cb --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/components/UserItem.js @@ -0,0 +1,63 @@ +import styles from '../../scss/user-item.scss'; +import { createDivEl, protectFromXSS, timestampFromNow, toggleClass } from '../utils'; + +class UserItem { + constructor({ user, handler }) { + this.user = user; + this.element = this._createElement(handler); + } + + get userId() { + return this.user.userId; + } + + get nickname() { + return protectFromXSS(this.user.nickname); + } + + get profileUrl() { + return protectFromXSS(this.user.profileUrl); + } + + get lastSeenTimeString() { + return this.user.lastSeenAt ? timestampFromNow(this.user.lastSeenAt) : ''; + } + + get isOnline() { + return this.user.connectionStatus === 'online'; + } + + _createElement(handler) { + const item = createDivEl({ className: styles['user-item'], id: this.userId }); + + const userInfo = createDivEl({ className: styles['user-info'] }); + item.appendChild(userInfo); + const profile = createDivEl({ className: styles['user-profile'], background: this.profileUrl }); + userInfo.appendChild(profile); + const nickname = createDivEl({ className: styles['user-nickname'], content: this.nickname }); + userInfo.appendChild(nickname); + const isOnline = createDivEl({ + className: this.isOnline ? [styles['user-online'], styles.active] : styles['user-online'] + }); + userInfo.appendChild(isOnline); + + const userState = createDivEl({ className: styles['user-state'] }); + item.appendChild(userState); + const lastSeenTime = createDivEl({ className: styles['user-time'], content: this.lastSeenTimeString }); + userState.appendChild(lastSeenTime); + const selectIcon = createDivEl({ className: styles['user-select'] }); + userState.appendChild(selectIcon); + item.addEventListener('click', () => { + toggleClass(item.querySelector(`.${UserItem.selectIconClassName}`), styles.active); + if (handler) handler(); + }); + + return item; + } + + static get selectIconClassName() { + return styles['user-select']; + } +} + +export { UserItem }; diff --git a/javascript/javascript-basic-syncmanager/src/js/components/UserList.js b/javascript/javascript-basic-syncmanager/src/js/components/UserList.js new file mode 100644 index 00000000..a93c9837 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/components/UserList.js @@ -0,0 +1,128 @@ +import styles from '../../scss/user-list.scss'; +import { createDivEl, errorAlert, appendToFirst } from '../utils'; +import { List } from './List'; +import { Spinner } from './Spinner'; +import { SendBirdAction } from '../SendBirdAction'; +import { UserItem } from './UserItem'; +import { Chat } from '../Chat'; +import { ChatLeftMenu } from '../ChatLeftMenu'; + +let instance = null; + +class UserList extends List { + constructor() { + super('User List'); + if (instance) { + return instance; + } + + this.scrollEventHandler = this._getUserList; + this.closeEventHandler = this._close; + this.createBtn = this._addCreateBtn(); + this.selectedUserIds = []; + instance = this; + } + + _addCreateBtn() { + const createBtn = createDivEl({ className: styles['button-create'], content: 'CREATE' }); + const oldCreateBtn = this.buttonRootElement.getElementsByClassName(styles['button-create'])[0]; + if (oldCreateBtn) { + this.buttonRootElement.removeChild(oldCreateBtn); + } + appendToFirst(this.buttonRootElement, createBtn); + return createBtn; + } + + _createChannel() { + SendBirdAction.getInstance() + .createGroupChannel(this.selectedUserIds) + .then(channel => { + ChatLeftMenu.getInstance().activeChannelUrl = channel.url; + Chat.getInstance().render(channel, false); + Spinner.remove(); + this.close(); + }) + .catch(error => { + Spinner.remove(); + errorAlert(error.message); + }); + } + + _inviteChannel() { + const channelUrl = Chat.getInstance().channel.url; + SendBirdAction.getInstance() + .inviteGroupChannel(channelUrl, this.selectedUserIds) + .then(() => { + Spinner.remove(); + this.close(); + }) + .catch(error => { + Spinner.remove(); + errorAlert(error.message); + }); + } + + _updateCreateType(isInvite) { + this.createBtn = this._addCreateBtn(); + this.createBtn.innerHTML = isInvite ? 'INVITE' : 'CREATE'; + this.createBtn.addEventListener('click', () => { + Spinner.start(this.element); + if (isInvite) { + this._inviteChannel(); + } else { + this._createChannel(); + } + }); + } + + _getUserList(isInit = false) { + Spinner.start(this.element); + const sendbirdAction = SendBirdAction.getInstance(); + const listContent = this.getContentElement(); + sendbirdAction + .getUserList(isInit) + .then(userList => { + userList.forEach(user => { + if (!sendbirdAction.isCurrentUser(user)) { + const handler = () => { + this._toggleUserId(item.userId); + }; + const item = new UserItem({ user, handler }); + listContent.appendChild(item.element); + } + }); + Spinner.remove(); + }) + .catch(error => { + Spinner.remove(); + errorAlert(error.message); + }); + } + + _toggleUserId(userId) { + const index = this.selectedUserIds.indexOf(userId); + if (index > -1) { + this.selectedUserIds.splice(index, 1); + } else { + this.selectedUserIds.push(userId); + } + } + + _close() { + this.selectedUserIds = []; + } + + render(isInvite = false) { + if (!document.body.querySelector(`.${this.getRootClassName()}`)) { + this._updateCreateType(isInvite); + document.body.appendChild(this.element); + this._getUserList(true); + } + } + + static getInstance() { + return new UserList(); + } +} + +export { UserList }; diff --git a/javascript/javascript-basic-syncmanager/src/js/const.js b/javascript/javascript-basic-syncmanager/src/js/const.js new file mode 100644 index 00000000..f4d5f183 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/const.js @@ -0,0 +1,11 @@ +export const APP_ID = '9DA1B1F4-0BE6-4DA8-82C5-2E81DAB56F23'; +export const USER_ID = 'user_id'; +export const DISPLAY_NONE = 'none'; +export const DISPLAY_BLOCK = 'block'; +export const DISPLAY_FLEX = 'flex'; +export const ACTIVE_CLASSNAME = 'active'; +export const KEY_ENTER = 13; +export const FILE_ID = 'attach_file_id'; +export const UPDATE_INTERVAL_TIME = 5 * 1000; +export const COLOR_RED = '#DC5960'; +export const MESSAGE_REQ_ID = 'reqId'; diff --git a/javascript/javascript-basic-syncmanager/src/js/index.js b/javascript/javascript-basic-syncmanager/src/js/index.js new file mode 100644 index 00000000..5cbeefcf --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/index.js @@ -0,0 +1,36 @@ +import { isEmpty, setCookie, getCookie } from './utils'; +import { USER_ID, KEY_ENTER } from './const'; + +const userIdEl = document.querySelector('#user_id'); +const nicknameEl = document.querySelector('#user_nickname'); +const buttonEl = document.querySelector('#login-button'); + +document.addEventListener('DOMContentLoaded', () => { + const cookieUserId = getCookie(USER_ID); + if (cookieUserId) { + userIdEl.value = cookieUserId; + } +}); + +nicknameEl.addEventListener('keydown', e => { + if (e.which === KEY_ENTER) { + login(); + } +}); + +buttonEl.addEventListener('click', () => { + login(); +}); + +const login = () => { + const userId = userIdEl.value.trim(); + const nickname = nicknameEl.value.trim(); + if (isEmpty(nickname)) { + alert('Please enter user nickname'); + return; + } + userIdEl.value = ''; + nicknameEl.value = ''; + setCookie(USER_ID, userId); + window.location.href = `chat.html?userid=${encodeURIComponent(userId)}&nickname=${encodeURIComponent(nickname)}`; +}; diff --git a/javascript/javascript-basic-syncmanager/src/js/main.js b/javascript/javascript-basic-syncmanager/src/js/main.js new file mode 100644 index 00000000..55ff7f94 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/main.js @@ -0,0 +1,71 @@ +import { getVariableFromUrl, isEmpty, redirectToIndex } from './utils'; +import { SendBirdAction } from './SendBirdAction'; +import { SendBirdConnection } from './SendBirdConnection'; +import { ChatLeftMenu } from './ChatLeftMenu'; +import { Chat } from './Chat'; +import { UPDATE_INTERVAL_TIME } from './const'; +import { LeftListItem } from './components/LeftListItem'; + +import SendBirdSyncManager from 'sendbird-syncmanager'; +import { Toast } from './components/Toast'; + +const sb = new SendBirdAction(); + +let chat = null; +let chatLeft = null; + +const createConnectionHandler = () => { + const manager = SendBirdSyncManager.getInstance(); + const connectionManager = new SendBirdConnection(); + connectionManager.onReconnectStarted = () => { + Toast.start(document.body, 'Connection is lost. Trying to reconnect...'); + connectionManager.channel = chat.channel; + }; + connectionManager.onReconnectSucceeded = () => { + chatLeft.updateUserInfo(SendBirdAction.getInstance().getCurrentUser()); + Toast.remove(); + manager.resumeSync(); + }; + connectionManager.onReconnectFailed = () => { + connectionManager.reconnect(); + }; +}; + +const updateGroupChannelTime = () => { + setInterval(() => { + LeftListItem.updateLastMessageTime(); + }, UPDATE_INTERVAL_TIME); +}; + +document.addEventListener('DOMContentLoaded', () => { + const { userid, nickname } = getVariableFromUrl(); + if (isEmpty(userid) || isEmpty(nickname)) { + redirectToIndex('UserID and Nickname must be required.'); + } + + SendBirdSyncManager.sendBird = sb.sb; + const options = new SendBirdSyncManager.Options(); + options.messageCollectionCapacity = 2000; + options.messageResendPolicy = 'automatic'; + options.automaticMessageResendRetryCount = 5; + options.maxFailedMessageCountPerChannel = 50; + options.failedMessageRetentionDays = 7; + SendBirdSyncManager.setup(userid, options, () => { + chat = new Chat(); + chatLeft = new ChatLeftMenu(); + updateGroupChannelTime(); + chatLeft.loadGroupChannelList(true); + + sb.connect( + userid, + nickname + ) + .then(user => { + chatLeft.updateUserInfo(user); + createConnectionHandler(); + }) + .catch(() => { + Toast.start(document.body, 'Connection is not established.'); + }); + }); +}); diff --git a/javascript/javascript-basic-syncmanager/src/js/utils.js b/javascript/javascript-basic-syncmanager/src/js/utils.js new file mode 100644 index 00000000..73310dc3 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/js/utils.js @@ -0,0 +1,231 @@ +import moment from 'moment'; + +export function findChannelIndex(newChannel, channels) { + const newChannelLastMessageUpdated = newChannel.lastMessage ? newChannel.lastMessage.createdAt : newChannel.createdAt; + + let index = channels.length; + for (let i = 0; i < channels.length; i++) { + const comparedChannel = channels[i]; + const comparedChannelLastMessageUpdated = comparedChannel.lastMessage + ? comparedChannel.lastMessage.createdAt + : comparedChannel.createdAt; + if (newChannel.url === comparedChannel.url) { + index = i; + break; + } else if (newChannelLastMessageUpdated > comparedChannelLastMessageUpdated) { + index = i; + break; + } + } + return index; +} +export function findMessageIndex(newMessage, messages, isRequestId = false) { + let index = messages.length; + for (let i = 0; i < messages.length; i++) { + if ( + !isRequestId && + newMessage.messageId !== 0 && + messages[i].messageId !== 0 && + messages[i].messageId === newMessage.messageId + ) { + index = i; + break; + } else if (isRequestId && messages[i].reqId === newMessage.reqId) { + index = i; + break; + } else if (messages[i].createdAt >= newMessage.createdAt) { + index = i; + break; + } + } + return index; +} + +export function mergeFailedWithSuccessful(failedMessages, successfulMessages) { + const wholeMessages = [...successfulMessages]; + for (let i = 0; i < failedMessages.length; i++) { + const index = findMessageIndex(failedMessages[i], wholeMessages); + wholeMessages.splice(index, 0, failedMessages[i]); + } + return wholeMessages; +} + +export const timestampToTime = timestamp => { + const now = new Date().getTime(); + const nowDate = moment.unix(now.toString().length === 13 ? now / 1000 : now).format('MM/DD'); + + let date = moment.unix(timestamp.toString().length === 13 ? timestamp / 1000 : timestamp).format('MM/DD'); + if (date === 'Invalid date') { + date = ''; + } + + return nowDate === date + ? moment.unix(timestamp.toString().length === 13 ? timestamp / 1000 : timestamp).format('HH:mm') + : date; +}; + +export const timestampToDateString = timestamp => { + return moment.unix(timestamp.toString().length === 13 ? timestamp / 1000 : timestamp).format('LL'); +}; + +export const timestampFromNow = timestamp => { + return moment(timestamp).fromNow(); +}; + +export const isUrl = urlString => { + const regex = /^(http|https):\/\/[^ "]+$/; + return regex.test(urlString); +}; + +export const isImage = fileType => { + const regex = /^image\/.+$/; + return regex.test(fileType); +}; + +export const isEmpty = value => { + return value === null || value === undefined || value.length === 0; +}; + +export const isNull = value => { + try { + return value === null; + } catch (e) { + return false; + } +}; + +export const setCookie = (key, value) => { + document.cookie = `${key}=${value}; expires=Fri, 31 Dec 9999 23:59:59 GMT`; +}; + +export const getCookie = key => { + let name = `${key}=`; + let ca = document.cookie.split(';'); + for (let i = 0; i < ca.length; i++) { + let c = ca[i]; + if (!c) continue; + while (c.charAt(0) === ' ') { + c = c.substring(1); + } + if (c.indexOf(name) === 0) { + return c.substring(name.length, c.length); + } + } + return ''; +}; + +export const getVariableFromUrl = () => { + let vars = {}; + let hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); + for (let i = 0; i < hashes.length; i++) { + let hash = hashes[i].split('='); + vars[hash[0]] = hash[1]; + } + return vars; +}; + +export const errorAlert = (message, reload = false) => { + // alert(message); + // eslint-disable-next-line no-console + console.error(message); + if (reload) { + location.reload(true); + } +}; + +export const redirectToIndex = message => { + if (message) { + errorAlert(message, false); + } + window.location.href = 'index.html'; +}; + +export const setDataInElement = (target, key, data) => { + target.dataset[`${key}`] = data; +}; + +export const getDataInElement = (target, key) => { + return target.dataset[`${key}`]; +}; + +export const createDivEl = ({ id, className, content, background }) => { + const el = document.createElement('div'); + if (id) { + el.id = id; + } + if (className) { + el.className = Array.isArray(className) ? className.join(' ') : className; + } + if (content) { + el.innerHTML = content; + } + if (background) { + el.style.backgroundImage = `url(${background})`; + } + return el; +}; + +export const isScrollBottom = target => { + return target.scrollTop + target.offsetHeight >= target.scrollHeight; +}; + +export const appendToFirst = (target, newElement) => { + if (target.childNodes.length > 0) { + target.insertBefore(newElement, target.childNodes[0]); + } else { + target.appendChild(newElement); + } +}; + +const hasClass = (target, className) => { + return target.classList + ? target.classList.contains(className) + : new RegExp('(^| )' + className + '( |$)', 'gi').test(target.className); +}; + +export const addClass = (target, className) => { + if (target.classList) { + if (!(className in target.classList)) { + target.classList.add(className); + } + } else { + if (target.className.indexOf(className) < 0) { + target.className += ` ${className}`; + } + } +}; + +export const removeClass = (target, className) => { + if (target.classList) { + target.classList.remove(className); + } else { + target.className = target.className.replace( + new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), + '' + ); + } +}; + +export const toggleClass = (target, className) => { + hasClass(target, className) ? removeClass(target, className) : addClass(target, className); +}; + +export const uuid4 = () => { + let d = new Date().getTime(); + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + const r = (d + Math.random() * 16) % 16 | 0; + d = Math.floor(d / 16); + return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16); + }); +}; + +export const protectFromXSS = text => { + return typeof text === 'string' + ? text + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, ''') + : text; +}; diff --git a/javascript/javascript-basic-syncmanager/src/scss/_animation.scss b/javascript/javascript-basic-syncmanager/src/scss/_animation.scss new file mode 100644 index 00000000..75dad441 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/_animation.scss @@ -0,0 +1,40 @@ +// Mixin +@mixin keyframes($name) { + @-webkit-keyframes #{$name} { @content; } + @-moz-keyframes #{$name} { @content; } + @-o-keyframes #{$name} { @content; } + @-ms-keyframes #{$name} { @content; } + @keyframes #{$name} { @content; } +} + +@mixin transition($options...) { + -webkit-transition: $options; + -moz-transition: $options; + -ms-transition: $options; + -o-transition: $options; + transition: $options; +} + +@mixin transform-scale($size) { + -webkit-transform: scale($size); + -moz-transform: scale($size); + -ms-transform: scale($size); + -o-transform: scale($size); + transform: scale($size); +} + +@mixin animation($animation...) { + -webkit-animation: $animation; + -moz-animation: $animation; + -o-animation: $animation; + -ms-animation: $animation; + animation: $animation; +} + +@mixin animation-delay($delay) { + -webkit-animation-delay: $delay; + -moz-animation-delay: $delay; + -o-animation-delay: $delay; + -ms-animation-delay: $delay; + animation-delay: $delay; +} diff --git a/javascript/javascript-basic-syncmanager/src/scss/_common.scss b/javascript/javascript-basic-syncmanager/src/scss/_common.scss new file mode 100644 index 00000000..9727b042 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/_common.scss @@ -0,0 +1,10 @@ +@import 'normalize'; +@import 'variables'; +@import 'mixins'; +@import 'icons'; + +body { + display: flex; + font-family: $font-family-exo2; + -webkit-font-smoothing: antialiased; +} diff --git a/javascript/javascript-basic-syncmanager/src/scss/_icons.scss b/javascript/javascript-basic-syncmanager/src/scss/_icons.scss new file mode 100644 index 00000000..01c41b28 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/_icons.scss @@ -0,0 +1,40 @@ +// Icons +$ic-prefix: 'https://dxstmhyqfqr1o.cloudfront.net/web-basic/'; +$ic-input-user: 'icon-username-landing.svg'; +$ic-profile-default: 'image-profile.svg'; +$ic-add-normal: 'icon-add-normal.png'; +$ic-add-over: 'icon-add-over.png'; +$ic-close: 'icon-close.png'; +$ic-enter: 'icon-enter.png'; +$ic-check-unselect: 'icon-check-unselect.png'; +$ic-check-select: 'icon-check-select.png'; +$ic-empty-chat: 'img-empty.svg'; + +$ic-group: 'icon-group.png'; +$ic-hide-normal: 'icon-hide-normal.png'; +$ic-hide: 'icon-hide.png'; +$ic-group-add-normal: 'icon-group-add-normal.png'; +$ic-group-add: 'icon-group-add.png'; +$ic-leave-normal: 'icon-leave-normal.png'; +$ic-leave: 'icon-leave.png'; +$ic-attach-file-normal: 'icon-attach-file-normal.png'; +$ic-attach-file: 'icon-attach-file.png'; +$ic-arrow-normal: 'icon-arrow-nomal.png'; +$ic-arrow: 'icon-arrow.png'; +$ic-back: 'icon-back.png'; + +$ic-search: 'icon-search-nomal.png'; +$ic-search-over: 'icon-search-over.png'; + +@mixin icon($url, $size: cover, $position: center) { + background-image: url($ic-prefix + $url); + background-position: $position; + background-size: $size; + background-repeat: no-repeat; +} + +@mixin imageMessage() { + background-position: center; + background-size: 160px 160px; + background-repeat: no-repeat; +} \ No newline at end of file diff --git a/javascript/javascript-basic-syncmanager/src/scss/_mixins.scss b/javascript/javascript-basic-syncmanager/src/scss/_mixins.scss new file mode 100644 index 00000000..a954ed4b --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/_mixins.scss @@ -0,0 +1,4 @@ +@import 'mixins/border-radius'; +@import 'mixins/state'; +@import 'mixins/transform'; +@import 'mixins/reset'; diff --git a/javascript/javascript-basic-syncmanager/src/scss/_normalize.scss b/javascript/javascript-basic-syncmanager/src/scss/_normalize.scss new file mode 100644 index 00000000..08e68694 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/_normalize.scss @@ -0,0 +1,450 @@ +/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */ + +/* Document + ========================================================================== */ + +/** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in + * IE on Windows Phone and in iOS. + */ + +html { + line-height: 1.15; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/* Sections + ========================================================================== */ + +/** + * Remove the margin in all browsers (opinionated). + */ + +body { + margin: 0; +} + +/** + * Add the correct display in IE 9-. + */ + +article, +aside, +footer, +header, +nav, +section { + display: block; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/* Grouping content + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + * 1. Add the correct display in IE. + */ + +figcaption, +figure, +main { + /* 1 */ + display: block; +} + +/** + * Add the correct margin in IE 8. + */ + +figure { + margin: 1em 40px; +} + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +pre { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/* Text-level semantics + ========================================================================== */ + +/** + * 1. Remove the gray background on active links in IE 10. + * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. + */ + +a { + background-color: transparent; /* 1 */ + -webkit-text-decoration-skip: objects; /* 2 */ +} + +/** + * 1. Remove the bottom border in Chrome 57- and Firefox 39-. + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} + +/** + * Prevent the duplicate application of `bolder` by the next rule in Safari 6. + */ + +b, +strong { + font-weight: inherit; +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct font style in Android 4.3-. + */ + +dfn { + font-style: italic; +} + +/** + * Add the correct background and color in IE 9-. + */ + +mark { + background-color: #ff0; + color: #000; +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + */ + +audio, +video { + display: inline-block; +} + +/** + * Add the correct display in iOS 4-7. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Remove the border on images inside links in IE 10-. + */ + +img { + border-style: none; +} + +/** + * Hide the overflow in IE. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change the font styles in all browsers (opinionated). + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font-family: sans-serif; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { + /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { + /* 1 */ + text-transform: none; +} + +/** + * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` + * controls in Android 4. + * 2. Correct the inability to style clickable types in iOS and Safari. + */ + +button, +html [type='button'], /* 1 */ +[type='reset'], +[type='submit'] { + -webkit-appearance: button; /* 2 */ +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type='button']::-moz-focus-inner, +[type='reset']::-moz-focus-inner, +[type='submit']::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +[type='button']:-moz-focusring, +[type='reset']:-moz-focusring, +[type='submit']:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Correct the padding in Firefox. + */ + +fieldset { + padding: 0.35em 0.75em 0.625em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * 1. Add the correct display in IE 9-. + * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Remove the default vertical scrollbar in IE. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10-. + * 2. Remove the padding in IE 10-. + */ + +[type='checkbox'], +[type='radio'] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type='number']::-webkit-inner-spin-button, +[type='number']::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type='search'] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. + */ + +[type='search']::-webkit-search-cancel-button, +[type='search']::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* Interactive + ========================================================================== */ + +/* + * Add the correct display in IE 9-. + * 1. Add the correct display in Edge, IE, and Firefox. + */ + +details, /* 1 */ +menu { + display: block; +} + +/* + * Add the correct display in all browsers. + */ + +summary { + display: list-item; +} + +/* Scripting + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + */ + +canvas { + display: inline-block; +} + +/** + * Add the correct display in IE. + */ + +template { + display: none; +} + +/* Hidden + ========================================================================== */ + +/** + * Add the correct display in IE 10-. + */ + +[hidden] { + display: none; +} diff --git a/javascript/javascript-basic-syncmanager/src/scss/_variables.scss b/javascript/javascript-basic-syncmanager/src/scss/_variables.scss new file mode 100644 index 00000000..346a8a67 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/_variables.scss @@ -0,0 +1,41 @@ +// Color +$color-transparent: transparent !default; + +$color-black-border: #2C2D30 !default; +$color-black: #000000 !default; +$color-black-text: #555555 !default; +$color-black-text-light: #abb8c4 !default; + +$color-gray-admin: #e8ecef !default; +$color-gray-dark: #dedede !default; +$color-gray: #e3e3e3 !default; +$color-gray-light: #F8F8F8 !default; + +$color-white: #ffffff !default; + +$color-blue-dark: #328fe6 !default; +$color-blue: #32c5e6 !default; + + +$color-purple-darker: #463c66 !default; +$color-purple-dark: #4E4273 !default; +$color-purple: #6e5baa !default; +$color-purple-light: #6742d6 !default; + +$color-purple-deep: #673AB7 !default; + +$color-purple-text-dark: #7F6DA0 !default; +$color-purple-text: #c7b0ff !default; +$color-purple-text-light: #A08DCE !default; + +$color-green-online: #00C853 !default; + +$color-red: #DC5960 !default; + +$color-chat-border: #e0e2e5 !default; +$color-chat-select: #f8f9fa !default; + +$color-message-not-sent: #e5e5e5; + +// Font +$font-family-exo2: 'Exo 2'; diff --git a/javascript/javascript-basic-syncmanager/src/scss/chat-body.scss b/javascript/javascript-basic-syncmanager/src/scss/chat-body.scss new file mode 100644 index 00000000..edfabbe2 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/chat-body.scss @@ -0,0 +1,35 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.chat-body { + display: flex; + flex-direction: column; + height: 100%; + max-height: calc(100vh - 180px); + overflow-y: auto; + overflow-x: hidden; + padding: 10px 0; + + & > .new-message-pop { + margin: 0px 10px; + display: flex; + width: inherit; + + position: sticky; + bottom: -10px; + background-color: $color-white; + border: 5px solid $color-blue; + border-radius: 10px; + + & > .new-message-pop-text { + margin-left: 30px; + height: 30px; + font-size: 24px; + color: $color-blue; + @include hover-focus { + cursor: pointer; + } + } + } +} diff --git a/javascript/javascript-basic-syncmanager/src/scss/chat-input.scss b/javascript/javascript-basic-syncmanager/src/scss/chat-input.scss new file mode 100644 index 00000000..089761eb --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/chat-input.scss @@ -0,0 +1,74 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.chat-input { + display: flex; + padding: 20px; + border-top: 1px solid $color-chat-border; + background-color: $color-white; + + & > .typing-field { + display: none; + position: absolute; + bottom: 79px; + left: 220px; + width: calc(100vw - 220px - 240px); + padding: 6px 20px; + box-sizing: border-box; + background-color: rgba(0, 0, 0, 0.1); + color: $color-black-text; + opacity: 0.4; + vertical-align: middle; + font-size: 13px; + font-style: italic; + } + + & > .input-file { + display: flex; + width: 36px; + height: 36px; + border: 1px solid $color-chat-border; + border-right: 0; + background-color: $color-white; + cursor: pointer; + @include border-left-radius(4px); + @include icon($ic-attach-file-normal, 20px 20px, center center); + @include hover-focus { + border: 1px solid $color-black-border; + @include icon($ic-attach-file, 20px 20px, center center); + } + } + + & > .input-text { + display: flex; + font-size: 15px; + width: 100%; + height: 38px; + padding: 7px 8px 6px 8px; + box-sizing: border-box; + border: 1px solid $color-chat-border; + background-color: $color-white; + @include border-right-radius(4px); + @include hover-focus-active { + border: 1px solid $color-black-border; + } + + & > .input-text-area { + width: 100%; + outline: none; + border: 0; + resize: none; + line-height: 1.4; + background-color: $color-white; + overflow: hidden; + @include hover-focus { + outline: none; + border: 0; + resize: none; + padding-top: 2px; + line-height: 1.4; + } + } + } +} diff --git a/javascript/javascript-basic-syncmanager/src/scss/chat-main.scss b/javascript/javascript-basic-syncmanager/src/scss/chat-main.scss new file mode 100644 index 00000000..34279652 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/chat-main.scss @@ -0,0 +1,18 @@ +@import 'mixins'; +@import 'variables'; + +.chat-main-root { + display: flex; + flex-direction: row; + height: 100%; + overflow-y: auto; + overflow-x: hidden; + padding: 0; + + & > .chat-main { + display: flex; + flex-direction: column; + justify-content: space-between; + width: 100%; + } +} diff --git a/javascript/javascript-basic-syncmanager/src/scss/chat-menu.scss b/javascript/javascript-basic-syncmanager/src/scss/chat-menu.scss new file mode 100644 index 00000000..b54403ae --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/chat-menu.scss @@ -0,0 +1,97 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.chat-menu-root { + display: flex; + flex-direction: column; + width: 240px; + min-width: 240px; + max-width: 240px; + background-color: $color-white; + box-sizing: border-box; + border-left: 1px solid $color-chat-border; + color: $color-black-border; + padding: 0; + + & > .menu-item { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + align-content: center; + padding: 10px 20px; + border-bottom: 1px solid $color-chat-border; + cursor: pointer; + + & > .menu-users, + & > .menu-blocked { + display: flex; + opacity: 0.6; + } + + & > .menu-arrow { + display: flex; + width: 36px; + height: 36px; + @include icon($ic-arrow-normal, 26px 26px, center center); + } + + @include hover-focus { + background-color: $color-chat-select; + + & > .menu-users, + & > .menu-blocked { + opacity: 1; + } + + & > .menu-arrow { + @include icon($ic-arrow, 26px 26px, center center); + } + } + } + + & > .menu-list { + display: none; + flex-direction: column; + position: absolute; + width: 239px; + height: calc(100% - 77px); + background: $color-white; + z-index: 999; + + & > .list-title { + display: flex; + align-items: center; + align-content: center; + padding: 10px 20px; + box-sizing: border-box; + color: $color-black-border; + border-bottom: 1px solid $color-chat-border; + cursor: pointer; + @include hover-focus { + background-color: $color-chat-select; + } + + & > .list-back { + display: flex; + width: 36px; + height: 36px; + @include icon($ic-back, 24px 24px, 0 center); + } + + & > .list-text { + display: flex; + } + } + + & > .list-body { + display: block; + flex-direction: column; + height: 100%; + max-height: calc(100% - 56px); + overflow-y: auto; + overflow-x: hidden; + } + } +} diff --git a/javascript/javascript-basic-syncmanager/src/scss/chat-top-menu.scss b/javascript/javascript-basic-syncmanager/src/scss/chat-top-menu.scss new file mode 100644 index 00000000..239bb56c --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/chat-top-menu.scss @@ -0,0 +1,81 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.chat-top { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + height: 80px; + box-sizing: border-box; + padding: 15px 20px; + border: 1px solid transparent; + border-bottom: 1px solid $color-chat-border; + color: $color-black-border; + + & > .chat-title { + max-width: 800px; + font-size: 20px; + white-space: nowrap; + overflow: hidden; + -ms-text-overflow: ellipsis; + text-overflow: ellipsis; + } + & > .chat-title.is-group { + padding-left: 34px; + @include icon($ic-group, 27px 27px, 0 center); + } + + & > .chat-button { + display: flex; + flex-direction: row; + justify-content: flex-end; + width: 150px; + margin-left: 20px; + + & > .button-invite { + width: 36px; + height: 36px; + border: 1px solid $color-chat-border; + margin-right: 10px; + cursor: pointer; + @include border-radius(4px); + @include icon($ic-group-add-normal, 20px 20px, center center); + @include hover-focus { + cursor: pointer; + border: 1px solid $color-black-border; + @include icon($ic-group-add, 20px 20px, center center); + } + } + + & > .button-hide { + width: 36px; + height: 36px; + border: 1px solid $color-chat-border; + margin-right: 10px; + cursor: pointer; + @include border-radius(4px); + @include icon($ic-hide-normal, 20px 20px, center center); + @include hover-focus { + cursor: pointer; + border: 1px solid $color-black-border; + @include icon($ic-hide, 20px 20px, center center); + } + } + + & > .button-leave { + width: 36px; + height: 36px; + border: 1px solid $color-chat-border; + cursor: pointer; + @include border-radius(4px); + @include icon($ic-leave-normal, 20px 20px, center center); + @include hover-focus { + cursor: pointer; + border: 1px solid $color-black-border; + @include icon($ic-leave, 20px 20px, center center); + } + } + } +} diff --git a/javascript/javascript-basic-syncmanager/src/scss/chat-user-item.scss b/javascript/javascript-basic-syncmanager/src/scss/chat-user-item.scss new file mode 100644 index 00000000..649deefb --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/chat-user-item.scss @@ -0,0 +1,34 @@ +@import 'mixins'; +@import 'variables'; + +.chat-user-item { + display: flex; + flex-direction: row; + align-items: center; + padding: 10px 20px; + cursor: pointer; + + & > .user-image { + display: flex; + width: 36px; + height: 36px; + margin-right: 10px; + background-size: 36px 36px; + background-position: center center; + background-repeat: no-repeat; + @include border-radius(50%); + } + + & > .user-nickname { + width: 154px; + max-width: 154px; + white-space: nowrap; + overflow: hidden; + -ms-text-overflow: ellipsis; + text-overflow: ellipsis; + } + & > .user-nickname.is-user { + font-weight: 600; + color: $color-purple-deep; + } +} diff --git a/javascript/javascript-basic-syncmanager/src/scss/chat.scss b/javascript/javascript-basic-syncmanager/src/scss/chat.scss new file mode 100644 index 00000000..9c9242ae --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/chat.scss @@ -0,0 +1,51 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.chat-empty { + display: flex; + width: 100%; + height: 100%; + + & > .empty-content { + display: flex; + flex-direction: column; + align-items: center; + margin: auto; + text-align: center; + color: $color-black-text-light; + @include transform-translate(0, -50%); + + & > .content-title { + display: flex; + font-size: 28px; + } + + & > .content-image { + display: flex; + width: 80px; + height: 80px; + padding: 8px; + @include icon($ic-empty-chat, 80px 80px, center center); + } + + & > .content-desc { + display: flex; + font-size: 14px; + white-space: pre; + } + } +} + +.logo-image { + background-color: $color-white; + border-radius: 50%; +} + +.chat-root { + display: flex; + flex-direction: column; + justify-content: flex-start; + width: 100%; + height: 100%; +} diff --git a/javascript/javascript-basic-syncmanager/src/scss/index.scss b/javascript/javascript-basic-syncmanager/src/scss/index.scss new file mode 100644 index 00000000..c504b226 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/index.scss @@ -0,0 +1,146 @@ +@import 'common'; + +body { + background-color: $color-purple; +} + +.logo-image { + background-color: $color-white; + border-radius: 50%; +} + +.container { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + min-width: 900px; + min-height: 650px; + font-family: $font-family-exo2; + + &>.top { + display: flex; + justify-content: center; + align-items: center; + margin-top: 80px; + color: $color-white; + + &>.logo { + display: flex; + align-items: center; + background-color: $color-white; + width: 87px; + height: 87px; + flex-direction: column; + justify-content: center; + @include border-radius(50%); + + &>.logo-image { + display: flex; + align-items: center; + } + } + + &>.title { + display: flex; + align-items: center; + + &>.title-company { + display: flex; + align-items: center; + font-size: 30px; + font-weight: 600; + margin: 0 10px; + } + + &>.title-desc { + display: flex; + align-items: center; + font-size: 26px; + font-weight: 200; + } + } + } + + &>.login { + display: flex; + margin-top: 40px; + flex-direction: column; + justify-content: center; + align-items: center; + + &>.desc { + display: flex; + color: $color-purple-text; + flex-direction: column; + align-items: center; + text-align: center; + + &>.download { + display: flex; + text-align: center; + margin: 20px 0; + + &>.download-sample { + color: $color-purple-text; + cursor: pointer; + + @include hover { + cursor: pointer; + } + } + } + } + + &>.form { + display: flex; + flex-direction: column; + margin-top: 10px; + + &>.form-input { + display: flex; + margin-top: 10px; + border: 2px solid $color-white; + padding: 0 10px 0 40px; + width: 300px; + height: 50px; + font-size: 16px; + color: $color-black-text; + @include border-radius(2px); + @include icon($ic-input-user, 20px 20px, 10px center); + + @include hover-focus { + border: 2px solid $color-blue; + } + } + + &>.button { + display: flex; + justify-content: center; + margin-top: 10px; + width: 100%; + height: 48px; + background-color: $color-blue; + color: $color-white; + font-size: 16px; + font-weight: 700; + border: 0; + @include border-radius(2px); + cursor: pointer; + + @include hover { + cursor: pointer; + } + } + } + } + + &>.image { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + margin-top: 50px; + color: $color-white; + } +} \ No newline at end of file diff --git a/javascript/javascript-basic-syncmanager/src/scss/list-item.scss b/javascript/javascript-basic-syncmanager/src/scss/list-item.scss new file mode 100644 index 00000000..a476e87f --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/list-item.scss @@ -0,0 +1,84 @@ +@import 'mixins'; +@import 'variables'; + +.list-item { + display: flex; + flex-direction: column; + padding: 6px 20px; + cursor: pointer; + @include hover { + background-color: $color-purple-darker; + } + & > .item-top { + display: flex; + color: $color-purple-text-light; + & > .item-count { + width: 18px; + height: 18px; + box-sizing: border-box; + border: 1px solid $color-purple-text-light; + align-items: center; + align-content: center; + text-align: center; + margin-right: 8px; + font-size: 13px; + line-height: 17px; + } + & > .item-title { + width: 100%; + max-width: 150px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + } + } + & > .item-bottom { + display: flex; + color: $color-purple-text-dark; + justify-content: space-between; + flex-direction: column; + font-size: 14px; + margin-top: 4px; + padding-left: 26px; + & > .item-message { + display: flex; + flex-direction: row; + justify-content: space-between; + & > .item-message-text { + width: 130px; + max-width: 130px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + color: $color-purple-text-light; + opacity: 0.7; + } + & > .item-message-unread { + display: none; + width: 16px; + height: 16px; + background-color: $color-red; + text-align: center; + color: $color-white; + font-size: 10px; + font-weight: 600; + line-height: 16px; + @include border-radius(50%); + } + & > .item-message-unread.active { + display: block; + } + } + & > .item-time { + display: flex; + font-size: 11px; + } + } +} + +.list-item.active { + & > .item-top { + color: $color-purple-text; + font-weight: 600; + } +} diff --git a/javascript/javascript-basic-syncmanager/src/scss/list.scss b/javascript/javascript-basic-syncmanager/src/scss/list.scss new file mode 100644 index 00000000..7365ce94 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/list.scss @@ -0,0 +1,106 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.list-root { + min-width: 980px; + width: 100vw; + height: 100vh; + max-height: 100vh; + overflow: hidden; + position: absolute; + z-index: 9999; + background-color: $color-white; + font-family: $font-family-exo2; + & > .list-body { + max-width: 700px; + min-width: 500px; + width: 100%; + height: 100%; + margin: 70px auto 50px auto; + display: flex; + box-sizing: border-box; + flex-direction: column; + & > .list-top { + width: 100%; + height: 70px; + padding: 10px 20px; + box-sizing: border-box; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + & > .list-title { + display: flex; + font-size: 30px; + font-weight: 700; + margin-left: 20px; + } + & > .list-button { + display: flex; + flex-direction: row; + margin-right: 20px; + + & > .button-exit { + width: 36px; + height: 36px; + text-align: center; + justify-content: center; + display: flex; + line-height: 36px; + cursor: pointer; + border: 1px solid $color-black-border; + @include border-radius(4px); + @include icon($ic-close, 20px 20px, center center); + @include hover-focus { + cursor: pointer; + border: 1px solid $color-gray; + background-color: $color-gray; + } + } + } + } + & > .list-hr { + height: 0; + margin: 8px 20px; + border-top: 1px solid $color-gray; + } + + & > .list-search { + box-sizing: border-box; + padding: 10px 20px; + overflow: hidden; + & > .search-input { + font-size: 18px; + font-family: $font-family-exo2; + box-sizing: border-box; + width: calc(100% - 40px); + height: 42px; + margin: 0 20px; + padding-left: 44px; + outline: none; + border: 1px solid $color-gray; + @include border-radius(4px); + @include icon($ic-search, 26px 26px, 8px center); + @include hover-focus { + @include icon($ic-search-over, 26px 26px, 8px center); + border: 1px solid $color-purple-light; + font-weight: 300; + } + &::placeholder { + color: $color-gray; + font-size: 18px; + font-weight: 300; + } + } + } + + & > .list-content { + box-sizing: border-box; + padding: 10px 20px; + max-height: calc(100vh - 205px); + overflow-y: auto; + overflow-x: hidden; + } + } +} diff --git a/javascript/javascript-basic-syncmanager/src/scss/main.scss b/javascript/javascript-basic-syncmanager/src/scss/main.scss new file mode 100644 index 00000000..bc07b2e2 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/main.scss @@ -0,0 +1,163 @@ +@import 'common'; + +.body { + display: flex; + flex-direction: row; + width: 100%; + min-width: 980px; + font-family: $font-family-exo2; + + &>.body-left { + display: flex; + flex-direction: column; + justify-content: space-between; + width: 220px; + height: 100vh; + background-color: $color-purple-dark; + + &>.body-left-top { + display: flex; + padding: 20px; + justify-content: center; + + &>.top-logo { + display: flex; + align-items: center; + background-color: $color-white; + width: 50px; + height: 50px; + flex-direction: column; + justify-content: center; + @include border-radius(50%); + + &>.logo-image { + display: flex; + align-items: center; + } + } + + &>.top-text { + color: $color-white; + display: flex; + align-items: center; + font-size: 30px; + font-weight: 600; + margin-left: 5px; + } + } + + &>.body-left-list { + display: flex; + flex-direction: column; + height: calc(100vh - 170px); + color: $color-purple-text-dark; + + .icon-create-chat { + width: 20px; + height: 20px; + @include border-radius(4px); + @include icon($ic-add-normal, 17px 17px, center center); + + @include hover { + cursor: pointer; + background-color: $color-purple-text-light; + } + } + + &>.chat-type { + display: flex; + flex-direction: row; + justify-content: space-between; + font-family: $font-family-exo2; + font-weight: 400; + font-size: 14px; + color: #9F8DC0; + line-height: 20px; + padding: 8px 20px; + + &>.chat-type-title { + @include hover { + cursor: pointer; + font-weight: 600; + color: $color-purple-text-light; + } + } + } + + &>.chat-list { + flex-direction: column; + width: 100%; + max-height: 450px; + overflow-y: auto; + overflow-x: hidden; + box-sizing: border-box; + + &>.default-item { + display: block; + padding: 10px; + margin: 0 20px; + color: $color-purple-text-light; + font-size: 16px; + border: 1px dashed $color-purple-text-light; + @include border-radius(4px); + } + } + + &>.chat-list.chat-list-group { + max-height: calc(100% - 130px); + } + } + + &>.body-left-bottom { + display: flex; + padding: 20px; + background-color: $color-purple-darker; + + &>.bottom-profile { + display: flex; + height: 40px; + align-items: center; + + &>.image-profile { + display: flex; + align-items: center; + @include border-radius(50%); + } + } + + &>.bottom-nickname { + display: flex; + flex-direction: column; + justify-content: center; + padding-left: 10px; + + &>.nickname-title { + display: flex; + color: $color-purple-text-dark; + font-size: 14px; + } + + &>.nickname-content { + display: inline-block; + max-width: 150px; + height: 18px; + color: $color-purple-text-light; + font-size: 16px; + overflow: hidden; + text-overflow: ellipsis; + -ms-text-overflow: ellipsis; + white-space: nowrap; + } + } + } + } + + &>.body-center { + display: flex; + flex-direction: column; + width: 100%; + min-width: 500px; + height: 100%; + background-color: $color-white; + } +} \ No newline at end of file diff --git a/javascript/javascript-basic-syncmanager/src/scss/message-delete-modal.scss b/javascript/javascript-basic-syncmanager/src/scss/message-delete-modal.scss new file mode 100644 index 00000000..57c4db82 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/message-delete-modal.scss @@ -0,0 +1,14 @@ +@import 'mixins'; +@import 'variables'; + +.modal-message { + display: flex; + align-items: center; + padding: 10px 10px; + width: 100%; + border: 1px solid $color-red; + background-color: $color-white; + font-size: 18px; + margin: 10px 0; + @include border-radius(4px); +} diff --git a/javascript/javascript-basic-syncmanager/src/scss/message.scss b/javascript/javascript-basic-syncmanager/src/scss/message.scss new file mode 100644 index 00000000..504ab0d0 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/message.scss @@ -0,0 +1,110 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.chat-message { + display: block; + flex-direction: row; + justify-content: space-between; + align-items: center; + width: 100%; + box-sizing: border-box; + padding: 0 20px; + margin-bottom: 8px; + border: 1px solid transparent; + + & > .message-content { + display: inline; + & > .message-nickname { + align-items: center; + display: inline; + justify-content: flex-start; + flex-direction: column; + cursor: pointer; + } + & > .message-nickname.is-user { + font-weight: 600; + color: $color-purple-deep; + cursor: initial; + } + + & > .message-content { + display: inline; + white-space: pre-line; + } + & > .message-content.is-file { + cursor: pointer; + @include hover-focus { + color: $color-blue-dark; + } + } + + & > .time { + display: inline; + margin-left: 8px; + font-size: 12px; + opacity: 0.5; + } + & > .time.is-user { + cursor: pointer; + } + + & > .read { + display: none; + vertical-align: middle; + text-align: center; + width: 18px; + height: 18px; + line-height: 17px; + margin-left: 8px; + font-size: 12px; + color: $color-white; + font-weight: 500; + @include border-radius(50%); + background: $color-red; + } + & > .read.active { + display: inline-block; + } + & > .resend-button { + display: inline; + margin-left: 8px; + font-size: 12px; + cursor: pointer; + color: $color-red; + } + + & > .delete-button { + display: inline; + margin-left: 8px; + font-size: 12px; + cursor: pointer; + color: $color-red; + } + } + + & > .file-content { + display: block; + border-left: 2px solid $color-black-text; + padding-left: 10px; + margin-top: 8px; + cursor: pointer; + & > .file-render { + display: inline; + max-width: 300px; + max-height: 300px; + } + } + + & > .message-admin { + display: flex; + align-items: center; + width: 100%; + font-style: italic; + color: $color-black-text; + } +} + +.chat-message.is-failed { + background: $color-message-not-sent; +} diff --git a/web-widget/src/scss/mixins/_border-radius.scss b/javascript/javascript-basic-syncmanager/src/scss/mixins/_border-radius.scss similarity index 100% rename from web-widget/src/scss/mixins/_border-radius.scss rename to javascript/javascript-basic-syncmanager/src/scss/mixins/_border-radius.scss diff --git a/web-widget/src/scss/mixins/_reset.scss b/javascript/javascript-basic-syncmanager/src/scss/mixins/_reset.scss similarity index 100% rename from web-widget/src/scss/mixins/_reset.scss rename to javascript/javascript-basic-syncmanager/src/scss/mixins/_reset.scss diff --git a/javascript/javascript-basic-syncmanager/src/scss/mixins/_state.scss b/javascript/javascript-basic-syncmanager/src/scss/mixins/_state.scss new file mode 100644 index 00000000..94e4cea3 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/mixins/_state.scss @@ -0,0 +1,58 @@ +@mixin hover { + &:hover { @content; } +} + +@mixin plain-hover { + &, + &:hover { @content; } +} + +@mixin focus { + &:focus { @content; } +} + +@mixin plain-focus { + &, + &:focus { @content; } +} + +@mixin hover-focus { + &:hover, + &:focus { @content; } +} + +@mixin plain-hover-focus { + &, + &:hover, + &:focus { @content; } +} + +@mixin hover-focus-active { + &:hover, + &:focus, + &:active { @content; } +} + +@mixin after { + &::after { + @content + } +} + +@mixin before { + &::before { + @content + } +} + +@mixin before-after { + &::after, &::before { + @content + } +} + +@mixin plain-before-after { + &, &::after, &::before { + @content + } +} diff --git a/web-widget/src/scss/mixins/_transform.scss b/javascript/javascript-basic-syncmanager/src/scss/mixins/_transform.scss similarity index 100% rename from web-widget/src/scss/mixins/_transform.scss rename to javascript/javascript-basic-syncmanager/src/scss/mixins/_transform.scss diff --git a/javascript/javascript-basic-syncmanager/src/scss/modal.scss b/javascript/javascript-basic-syncmanager/src/scss/modal.scss new file mode 100644 index 00000000..3590e65d --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/modal.scss @@ -0,0 +1,74 @@ +@import 'mixins'; +@import 'variables'; + +.modal-root { + display: flex; + position: absolute; + width: 100vw; + height: 100vh; + z-index: 9999; + background-color: rgba(0, 0, 0, 0.5); + + & > .modal-body { + display: flex; + flex-direction: column; + box-sizing: border-box; + width: 450px; + background-color: $color-white; + margin: auto; + padding: 24px; + @include border-radius(4px); + @include transform-translate(0, -50%); + + & > .modal-title { + display: flex; + font-size: 26px; + font-weight: 600; + margin-bottom: 8px; + } + + & > .modal-desc { + display: flex; + color: $color-black-text; + font-size: 14px; + font-weight: 300; + } + + & > .modal-content { + display: flex; + margin: 10px 0; + } + + & > .modal-bottom { + display: flex; + justify-content: flex-end; + & > .modal-cancel { + display: flex; + margin-right: 12px; + color: $color-black-text-light; + border: 1px solid $color-black-text-light; + cursor: pointer; + padding: 6px; + @include border-radius(4px); + @include hover-focus { + color: $color-purple-light; + border: 1px solid $color-purple-light; + } + } + & > .modal-submit { + display: flex; + color: $color-white; + background-color: $color-blue; + border: 1px solid $color-blue; + cursor: pointer; + padding: 6px; + font-weight: 600; + @include border-radius(4px); + @include hover-focus { + background-color: $color-blue-dark; + border: 1px solid $color-blue-dark; + } + } + } + } +} \ No newline at end of file diff --git a/javascript/javascript-basic-syncmanager/src/scss/spinner.scss b/javascript/javascript-basic-syncmanager/src/scss/spinner.scss new file mode 100644 index 00000000..7bf66632 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/spinner.scss @@ -0,0 +1,71 @@ +@import 'mixins'; +@import 'variables'; + +.sb-spinner { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + opacity: 0.6; + background-color: $color-white; + flex-direction: column; + justify-content: center; + display: flex; + + .sb-spinner-bubble { + color: $color-black; + font-size: 10px; + margin: 80px auto; + position: relative; + text-indent: -9999em; + -webkit-animation-delay: -0.16s; + animation-delay: -0.16s; + @include transform-translate(0, -2em); + @include plain-before-after { + @include border-radius(50%); + width: 1.5em; + height: 1.5em; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; + -webkit-animation: load7 1.8s infinite ease-in-out; + animation: load7 1.8s infinite ease-in-out; + } + @include before-after { + content: ''; + position: absolute; + top: 0; + } + @include before { + left: -3.5em; + -webkit-animation-delay: -0.32s; + animation-delay: -0.32s; + } + @include after { + left: 3.5em; + } + } + +} + +@-webkit-keyframes load7 { + 0%, + 80%, + 100% { + box-shadow: 0 2.5em 0 -1.3em; + } + 40% { + box-shadow: 0 2.5em 0 0; + } +} +@keyframes load7 { + 0%, + 80%, + 100% { + box-shadow: 0 2.5em 0 -1.3em; + } + 40% { + box-shadow: 0 2.5em 0 0; + } +} + diff --git a/javascript/javascript-basic-syncmanager/src/scss/toast.scss b/javascript/javascript-basic-syncmanager/src/scss/toast.scss new file mode 100644 index 00000000..112eaa3b --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/toast.scss @@ -0,0 +1,21 @@ +@import 'variables'; +@import 'animation'; + +.sb-toast { + position: fixed; + top: 0; + left: 0; + width: 100%; + text-align: center; + + .sb-toast-message { + color: $color-white; + display:inline-block; + font-size: 14px; + padding:10px 15px; + margin-top:20px; + border-radius:5px; + background-color: $color-purple-dark; + } +} + diff --git a/javascript/javascript-basic-syncmanager/src/scss/user-block-modal.scss b/javascript/javascript-basic-syncmanager/src/scss/user-block-modal.scss new file mode 100644 index 00000000..9df0631c --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/user-block-modal.scss @@ -0,0 +1,34 @@ +@import 'mixins'; +@import 'variables'; + +.modal-user { + display: flex; + align-items: center; + padding: 10px 10px; + width: 100%; + border: 1px solid $color-red; + background-color: $color-white; + font-size: 18px; + margin: 10px 0; + @include border-radius(4px); + + & > .user-profile { + display: flex; + width: 36px; + height: 36px; + margin-right: 10px; + background-size: 36px 36px; + background-position: center center; + background-repeat: no-repeat; + @include border-radius(50%); + } + + & > .user-nickname { + width: 330px; + max-width: 330px; + white-space: nowrap; + overflow: hidden; + -ms-text-overflow: ellipsis; + text-overflow: ellipsis; + } +} diff --git a/javascript/javascript-basic-syncmanager/src/scss/user-item.scss b/javascript/javascript-basic-syncmanager/src/scss/user-item.scss new file mode 100644 index 00000000..de417bfd --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/user-item.scss @@ -0,0 +1,77 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.user-item { + display: flex; + padding: 8px 20px 8px 20px; + border: 1px solid transparent; + border-bottom: 1px solid $color-gray-dark; + justify-content: space-between; + cursor: pointer; + @include hover-focus { + cursor: pointer; + border: 1px solid $color-purple-light; + @include border-radius(2px); + } + + & > .user-info { + display: flex; + align-items: center; + + & > .user-profile { + display: flex; + width: 40px; + height: 40px; + @include icon($ic-profile-default, 40px 40px, center center); + } + + & > .user-nickname { + margin: 0 10px; + font-size: 18px; + max-width: 250px; + overflow: hidden; + text-overflow: ellipsis; + -ms-text-overflow: ellipsis; + white-space: nowrap; + } + + & > .user-online { + display: flex; + width: 8px; + height: 8px; + border: 1px solid $color-black-text-light; + background-color: $color-black-text-light; + opacity: 0.4; + @include border-radius(50%); + } + & > .user-online.active { + border: 1px solid $color-green-online; + background-color: $color-green-online; + opacity: 1; + } + } + + & > .user-state { + display: flex; + align-items: center; + + & > .user-time { + display: flex; + color: $color-black-text-light; + margin-right: 10px; + } + + & > .user-select { + display: flex; + width: 30px; + height: 30px; + opacity: 0.4; + @include icon($ic-check-unselect, 30px 30px, center center); + } + & > .user-select.active { + opacity: 1; + @include icon($ic-check-select, 30px 30px, center center); + } + } +} diff --git a/javascript/javascript-basic-syncmanager/src/scss/user-list.scss b/javascript/javascript-basic-syncmanager/src/scss/user-list.scss new file mode 100644 index 00000000..bc99f7b4 --- /dev/null +++ b/javascript/javascript-basic-syncmanager/src/scss/user-list.scss @@ -0,0 +1,23 @@ +@import 'mixins'; +@import 'variables'; + +.button-create { + width: 80px; + height: 36px; + text-align: center; + justify-content: center; + display: flex; + line-height: 36px; + font-weight: 600; + color: $color-white; + cursor: pointer; + background-color: $color-blue; + border: 1px solid $color-blue; + margin-right: 12px; + @include border-radius(4px); + @include hover-focus { + cursor: pointer; + background-color: $color-blue-dark; + border: 1px solid $color-blue-dark; + } +} diff --git a/javascript/javascript-basic-syncmanager/webpack.config.js b/javascript/javascript-basic-syncmanager/webpack.config.js new file mode 100644 index 00000000..55375e1a --- /dev/null +++ b/javascript/javascript-basic-syncmanager/webpack.config.js @@ -0,0 +1,76 @@ +'use strict'; +const path = require('path'); +const ExtractTextPlugin = require('extract-text-webpack-plugin'); + +const PRODUCTION = 'production'; + +module.exports = () => { + const config = { + mode: 'production', + entry: { + index: ['./src/js/index.js', './src/scss/index.scss'], + main: ['./src/js/main.js', './src/scss/main.scss'] + }, + output: { + path: path.resolve(__dirname, './dist'), + filename: 'sample.[name].js', + library: '[name]', + libraryExport: 'default', + libraryTarget: 'umd', + publicPath: 'dist' + }, + devtool: 'cheap-eval-source-map', + devServer: { + publicPath: '/dist/', + compress: true, + port: 9000 + }, + performance: { hints: false }, + module: { + rules: [ + { + // SCSS + test: /\.scss$/, + use: ExtractTextPlugin.extract({ + fallback: 'style-loader', + use: [ + { + loader: 'css-loader', + options: { + module: true, + minimize: process.env.WEBPACK_MODE === PRODUCTION, + // sourceMap: true, + localIdentName: '[local]' + } + }, + { + loader: 'sass-loader' + } + ] + }) + }, + { + // ESLint + enforce: 'pre', + test: /\.js$/, + exclude: /node_modules/, + loader: 'eslint-loader', + options: { failOnError: true } + }, + { + // ES6 + test: /\.js$/, + loader: 'babel-loader', + exclude: '/node_modules/' + } + ] + }, + plugins: [ + new ExtractTextPlugin({ + filename: 'sample.[name].css' + }) + ] + }; + + return config; +}; diff --git a/javascript/javascript-basic/.babelrc b/javascript/javascript-basic/.babelrc new file mode 100644 index 00000000..a7352030 --- /dev/null +++ b/javascript/javascript-basic/.babelrc @@ -0,0 +1,8 @@ +{ + "presets": ["env"], + "env": { + "test": { + "presets": ["env"] + } + } +} diff --git a/javascript/javascript-basic/.eslintrc.js b/javascript/javascript-basic/.eslintrc.js new file mode 100644 index 00000000..0211a4b2 --- /dev/null +++ b/javascript/javascript-basic/.eslintrc.js @@ -0,0 +1,21 @@ +module.exports = { + env: { + browser: true, + commonjs: true, + es6: true + }, + extends: 'eslint:recommended', + parserOptions: { + parser: 'babel-eslint', + sourceType: 'module' + }, + rules: { + 'linebreak-style': ['error', 'unix'], + quotes: ['warn', 'single'], + semi: ['warn', 'always'], + 'no-console': 1, + 'no-unused-vars': 1, + 'no-inner-declarations': 1, + 'no-useless-escape': 1 + } +}; diff --git a/javascript/javascript-basic/.prettierignore b/javascript/javascript-basic/.prettierignore new file mode 100644 index 00000000..52999c0b --- /dev/null +++ b/javascript/javascript-basic/.prettierignore @@ -0,0 +1,2 @@ +README.md +.eslintrc.js \ No newline at end of file diff --git a/javascript/javascript-basic/.prettierrc b/javascript/javascript-basic/.prettierrc new file mode 100644 index 00000000..f65aabcb --- /dev/null +++ b/javascript/javascript-basic/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "printWidth": 120 +} \ No newline at end of file diff --git a/javascript/javascript-basic/README.md b/javascript/javascript-basic/README.md new file mode 100644 index 00000000..8b3a256f --- /dev/null +++ b/javascript/javascript-basic/README.md @@ -0,0 +1,60 @@ +# SendBird JavaScript Web Basic Sample +This is full screen chat sample like Slack using the [Sendbird SDK](https://github.com/sendbird/SendBird-SDK-JavaScript) for desktop browsers. + +1. [Demo](#demo) +1. [Run the sample](#run-the-sample) +1. [Customizing the sample](#customizing-the-sample) + +## [Demo](https://sample.sendbird.com/basic) +You can try out a live demo from the link [here](https://sample.sendbird.com/basic). + +> If you want to legacy basic sample used jQuery, you can find the [Legacy tag](https://github.com/sendbird/SendBird-JavaScript/tree/Legacy(WebBasic)). + + +## Run the sample +1. Install packages + +> Require that you have Node v8.x+ installed. + +> `node-sass` package requires XCode developer tools (MacOS only) and Node.js version matching. If you have any trouble in the installation, see https://www.npmjs.com/package/node-sass. + +```bash +npm install +``` + +2. Run + +```bash +npm start +``` + +## Customizing the sample +If you want to put some changes into the sample, you should build it using `webpack`. + +1. Install packages + +> Require that you have Node v8.x+ installed. + +> `node-sass` package requires XCode developer tools (MacOS only) and Node.js version matching. If you have any trouble in the installation, see https://www.npmjs.com/package/node-sass. + +```bash +npm install +``` + +2. Modify files +If you want to change `APP_ID`, change `APP_ID` in `./src/js/const.js` to the other `APP_ID` you want. +You can test the sample with local server by running the following command. + +```bash +npm run start:dev +``` + +3. Build the sample +When the modification is complete, you'll need to bundle the file using `webpack`. The bundled files are created in the `dist` folder. +Please check `webpack.config.js` for settings. + +```bash +npm run build +``` + +> The `npm start` command contains `npm run build`. Check the scripts part of the package.json file. diff --git a/javascript/javascript-basic/chat.html b/javascript/javascript-basic/chat.html new file mode 100644 index 00000000..6afa2110 --- /dev/null +++ b/javascript/javascript-basic/chat.html @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + Basic Sample | Sendbird + + + +
+
+
+ +
+ Sendbird +
+
+
+
+
OPEN CHAT
+
+
+
+
+
+
Start by selecting or creating a channel.
+
+
+
GROUP CHAT
+
+
+
+
+
+
Start by inviting user to create a channel.
+
+
+
+
+ +
+
+
username
+
+
+
+
+
+
+ + + + diff --git a/javascript/javascript-basic/index.html b/javascript/javascript-basic/index.html new file mode 100644 index 00000000..88dbc52c --- /dev/null +++ b/javascript/javascript-basic/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + Basic Sample | Sendbird + + + +
+
+ +
+
+ Sendbird +
+
+ Web Basic Sample +
+
+
+ +
+
+ Start chatting on Sendbird by choosing your display name. +
This can be changed anytime and will be shown on 1-on-1 and group messaging. + +
+
+ + + +
+
+ +
+ +
+
+ + + + diff --git a/javascript/javascript-basic/package.json b/javascript/javascript-basic/package.json new file mode 100644 index 00000000..8b06a0e2 --- /dev/null +++ b/javascript/javascript-basic/package.json @@ -0,0 +1,40 @@ +{ + "name": "Sample-JS-Web-Basic", + "version": "1.0.0", + "description": "Sendbird Web Basic Sample", + "main": "index.js", + "scripts": { + "dev": "./node_modules/.bin/webpack --mode=development", + "dev:w": "./node_modules/.bin/webpack --mode=none -w", + "build": "./node_modules/.bin/webpack --mode=production", + "start:dev": "./node_modules/.bin/webpack-dev-server", + "start": "npm run build && node server.js", + "deploy": "node ./deploy/deploy.js" + }, + "author": "SendBird", + "license": "ISC", + "devDependencies": { + "babel-core": "^6.26.0", + "babel-eslint": "^8.2.3", + "babel-loader": "^7.1.4", + "babel-polyfill": "^6.26.0", + "babel-preset-env": "^1.6.1", + "css-loader": "^0.28.11", + "eslint": "^4.19.1", + "eslint-loader": "^2.0.0", + "express": "^4.16.3", + "extract-text-webpack-plugin": "^4.0.0-beta.0", + "node-sass": "^4.11.0", + "prettier": "^1.15.3", + "sass-loader": "^7.1.0", + "ssh2": "^0.8.5", + "style-loader": "^0.21.0", + "webpack": "^4.6.0", + "webpack-cli": "^3.1.0", + "webpack-dev-server": "^3.1.11" + }, + "dependencies": { + "moment": "^2.22.1", + "sendbird": "^3.0.111" + } +} diff --git a/javascript/javascript-basic/server.js b/javascript/javascript-basic/server.js new file mode 100644 index 00000000..487ba47b --- /dev/null +++ b/javascript/javascript-basic/server.js @@ -0,0 +1,14 @@ +const express = require('express'); +const app = express(); + +const PORT = 9000; + +app.use(express.static('dist')); +app.use(express.static('./')); + +app.get('/', function(req, res) { + res.sendfile('index.html'); +}); + +app.listen(PORT); +console.log(`[SERVER RUNNING] 127.0.0.1:${PORT}`); diff --git a/javascript/javascript-basic/src/js/Chat.js b/javascript/javascript-basic/src/js/Chat.js new file mode 100644 index 00000000..9748e009 --- /dev/null +++ b/javascript/javascript-basic/src/js/Chat.js @@ -0,0 +1,169 @@ +import styles from '../scss/chat.scss'; +import { createDivEl, errorAlert } from './utils'; +import { SendBirdAction } from './SendBirdAction'; +import { Spinner } from './components/Spinner'; +import { ChatLeftMenu } from './ChatLeftMenu'; +import { ChatTopMenu } from './components/ChatTopMenu'; +import { ChatMain } from './components/ChatMain'; +import { SendBirdChatEvent } from './SendBirdChatEvent'; + +const targetEl = document.querySelector('.body-center'); + +let instance = null; + +class Chat { + constructor() { + if (instance) { + return instance; + } + + this.channel = null; + this.element = null; + this.top = null; + this.emptyElement = this._createEmptyElement(); + this.render(); + instance = this; + } + + _createEmptyElement() { + const item = createDivEl({ className: styles['chat-empty'] }); + + const content = createDivEl({ className: styles['empty-content'] }); + item.appendChild(content); + + const title = createDivEl({ className: styles['content-title'], content: 'WELCOME TO SAMPLE CHAT' }); + content.appendChild(title); + const image = createDivEl({ className: styles['content-image'] }); + content.appendChild(image); + const desc = createDivEl({ + className: styles['content-desc'], + content: + 'Create or select a channel to chat in.\n' + + "If you don't have a channel to participate,\n" + + 'go ahead and create your first channel now.' + }); + content.appendChild(desc); + return item; + } + + renderEmptyElement() { + this._removeChatElement(); + targetEl.appendChild(this.emptyElement); + } + + _removeEmptyElement() { + if (targetEl.contains(this.emptyElement)) { + targetEl.removeChild(this.emptyElement); + } + } + + _createChatElement(channel) { + this.element = createDivEl({ className: styles['chat-root'] }); + + this.top = new ChatTopMenu(channel); + this.element.appendChild(this.top.element); + + this.main = new ChatMain(channel); + } + + _addEventHandler() { + const channelEvent = new SendBirdChatEvent(); + channelEvent.onMessageReceived = (channel, message) => { + if (this.channel.url === channel.url) { + this.main.renderMessages([message], false); + } + }; + channelEvent.onMessageUpdated = (channel, message) => { + if (this.channel.url === channel.url) { + this.main.renderMessages([message], false); + } + }; + channelEvent.onMessageDeleted = (channel, messageId) => { + if (this.channel.url === channel.url) { + this.main.removeMessage(messageId, false); + } + }; + + if (this.channel.isGroupChannel()) { + channelEvent.onReadReceiptUpdated = groupChannel => { + if (this.channel.url === groupChannel.url) { + this.main.updateReadReceipt(); + } + }; + channelEvent.onTypingStatusUpdated = groupChannel => { + if (this.channel.url === groupChannel.url) { + this.main.updateTyping(groupChannel.getTypingMembers()); + } + }; + } + } + + _renderChatElement(channelUrl, isOpenChannel = true) { + Spinner.start(targetEl); + const sendbirdAction = SendBirdAction.getInstance(); + this._removeEmptyElement(); + this._removeChatElement(); + ChatLeftMenu.getInstance().activeChannelItem(channelUrl); + sendbirdAction + .getChannel(channelUrl, isOpenChannel) + .then(channel => { + this.channel = channel; + this._addEventHandler(); + this._createChatElement(this.channel); + targetEl.appendChild(this.element); + sendbirdAction + .getMessageList(this.channel, true) + .then(messageList => { + this.main.renderMessages(messageList); + if (this.channel.isGroupChannel()) { + sendbirdAction.markAsRead(this.channel); + } + Spinner.remove(); + }) + .catch(error => { + errorAlert(error.message); + }); + }) + .catch(error => { + errorAlert(error.message); + }); + } + + _removeChatElement() { + const chatElements = targetEl.getElementsByClassName(styles['chat-root']); + Array.prototype.slice.call(chatElements).forEach(chatEl => { + chatEl.parentNode.removeChild(chatEl); + }); + } + + updateChatInfo(channel) { + if (this.channel && this.channel.url === channel.url) { + if (this.top) { + this.top.updateTitle(channel); + } + if (this.main) { + this.main.updateMenu(channel); + } + } + } + + render(channelUrl, isOpenChannel = true) { + channelUrl ? this._renderChatElement(channelUrl, isOpenChannel) : this.renderEmptyElement(); + } + + refresh(channel) { + this._removeEmptyElement(); + this._removeChatElement(); + this.renderEmptyElement(); + const reconnectChannel = channel ? channel : this.channel; + if (reconnectChannel) { + this.render(reconnectChannel.url, reconnectChannel.isOpenChannel()); + } + } + + static getInstance() { + return new Chat(); + } +} + +export { Chat }; diff --git a/javascript/javascript-basic/src/js/ChatLeftMenu.js b/javascript/javascript-basic/src/js/ChatLeftMenu.js new file mode 100644 index 00000000..20fb7e1f --- /dev/null +++ b/javascript/javascript-basic/src/js/ChatLeftMenu.js @@ -0,0 +1,239 @@ +import { LeftListItem } from './components/LeftListItem'; +import { ACTIVE_CLASSNAME, body, DISPLAY_BLOCK, DISPLAY_NONE } from './const'; +import { addClass, appendToFirst, errorAlert, isScrollBottom, isUrl, protectFromXSS, removeClass } from './utils'; +import { Spinner } from './components/Spinner'; +import { OpenChannelList } from './components/OpenChannelList'; +import { SendBirdAction } from './SendBirdAction'; +import { UserList } from './components/UserList'; +import { Chat } from './Chat'; +import { OpenChannelCreateModal } from './components/OpenChannelCreateModal'; + +const openChannelBtn = document.querySelector('#open_chat'); +const openChannelCreateBtn = document.querySelector('#open_chat_add'); +const groupChannelCreateBtn = document.querySelector('#group_chat_add'); + +let instance = null; + +class ChatLeftMenu { + constructor() { + if (instance) { + return instance; + } + + this.openChannelList = document.getElementById('open_list'); + this.openChannelDefaultItem = document.getElementById('default_item_open'); + this.groupChannelList = document.getElementById('group_list'); + this.groupChannelList.addEventListener('scroll', () => { + if (isScrollBottom(this.groupChannelList)) { + this.getGroupChannelList(); + } + }); + this.groupChannelDefaultItem = document.getElementById('default_item_group'); + this._addEvent(); + instance = this; + } + + _addEvent() { + openChannelBtn.addEventListener('click', () => { + OpenChannelList.getInstance().render(); + }); + + openChannelCreateBtn.addEventListener('click', () => { + const title = 'Create Open Channel'; + const description = + 'Open Channel is a public chat. In this channel type, anyone can enter and participate in the chat without permission.'; + const submitText = 'CREATE'; + const openChannelCreateModal = new OpenChannelCreateModal({ title, description, submitText }); + openChannelCreateModal.render(); + }); + + groupChannelCreateBtn.addEventListener('click', () => { + UserList.getInstance().render(); + }); + } + + updateUserInfo(user) { + const userInfoEl = document.getElementById('user_info'); + const profileEl = userInfoEl.getElementsByClassName('image-profile')[0]; + if (isUrl(user.profileUrl)) { + profileEl.setAttribute('src', protectFromXSS(user.profileUrl)); + } + const nicknameEl = userInfoEl.getElementsByClassName('nickname-content')[0]; + nicknameEl.innerHTML = protectFromXSS(user.nickname); + } + + /** + * Item + */ + getChannelItem(channelUrl) { + const openItems = this.openChannelList.getElementsByClassName(LeftListItem.getItemRootClassName()); + const groupItems = this.groupChannelList.getElementsByClassName(LeftListItem.getItemRootClassName()); + const checkList = [...openItems, ...groupItems]; + for (let i = 0; i < checkList.length; i++) { + if (checkList[i].id === channelUrl) { + return checkList[i]; + } + } + return null; + } + + activeChannelItem(channelUrl) { + const openItems = this.openChannelList.getElementsByClassName(LeftListItem.getItemRootClassName()); + const groupItems = this.groupChannelList.getElementsByClassName(LeftListItem.getItemRootClassName()); + const checkList = [...openItems, ...groupItems]; + for (let i = 0; i < checkList.length; i++) { + checkList[i].id === channelUrl + ? addClass(checkList[i], ACTIVE_CLASSNAME) + : removeClass(checkList[i], ACTIVE_CLASSNAME); + } + } + + getItem(elementId) { + const openChannelItems = this.openChannelList.getElementsByClassName(LeftListItem.getItemRootClassName()); + for (let i = 0; i < openChannelItems.length; i++) { + if (openChannelItems[i].id === elementId) { + return openChannelItems[i]; + } + } + + const groupChannelItems = this.groupChannelList.getElementsByClassName(LeftListItem.getItemRootClassName()); + for (let i = 0; i < groupChannelItems.length; i++) { + if (groupChannelItems[i].id === elementId) { + return groupChannelItems[i]; + } + } + + return null; + } + + updateItem(channel, isFirst = false) { + const item = this.getItem(channel.url); + const handler = () => { + Chat.getInstance().render(channel.url, false); + ChatLeftMenu.getInstance().activeChannelItem(channel.url); + }; + const newItem = new LeftListItem({ channel, handler }); + const parentNode = this.groupChannelList; + if (isFirst) { + if (item) { + parentNode.removeChild(item); + } + appendToFirst(parentNode, newItem.element); + } else { + parentNode.replaceChild(newItem.element, item); + } + LeftListItem.updateUnreadCount(); + } + + /** + * Open Channel + */ + toggleOpenChannelDefaultItem() { + this.openChannelList.getElementsByClassName(LeftListItem.getItemRootClassName()).length > 0 + ? (this.openChannelDefaultItem.style.display = DISPLAY_NONE) + : (this.openChannelDefaultItem.style.display = DISPLAY_BLOCK); + } + + addOpenChannelItem(element) { + if (!this.openChannelList.contains(element)) { + this.openChannelList.appendChild(element); + } + this.toggleOpenChannelDefaultItem(); + } + + removeOpenChannelItem(elementId) { + const removeEl = this.getItem(elementId); + if (removeEl) { + this.openChannelList.removeChild(removeEl); + } + this.toggleOpenChannelDefaultItem(); + } + + /** + * Group Channel + */ + getGroupChannelList(isInit = false) { + Spinner.start(body); + SendBirdAction.getInstance() + .getGroupChannelList(isInit) + .then(groupChannelList => { + this.toggleGroupChannelDefaultItem(groupChannelList); + groupChannelList.forEach(channel => { + const handler = () => { + Chat.getInstance().render(channel.url, false); + ChatLeftMenu.getInstance().activeChannelItem(channel.url); + }; + const item = new LeftListItem({ channel, handler }); + this.groupChannelList.appendChild(item.element); + LeftListItem.updateUnreadCount(); + }); + Spinner.remove(); + }) + .catch(error => { + errorAlert(error.message); + }); + } + + toggleGroupChannelDefaultItem(items) { + if (items) { + this.groupChannelDefaultItem.style.display = items && items.length > 0 ? DISPLAY_NONE : DISPLAY_BLOCK; + } else { + this.groupChannelList.getElementsByClassName(LeftListItem.getItemRootClassName()).length > 0 + ? (this.groupChannelDefaultItem.style.display = DISPLAY_NONE) + : (this.groupChannelDefaultItem.style.display = DISPLAY_BLOCK); + } + } + + addGroupChannelItem(element, isFirst = false) { + const listItems = this.groupChannelList.childNodes; + let isExist = false; + for (let i = 0; i < listItems.length; i++) { + if (listItems[i].id === element.id) { + isExist = true; + } + } + if (isExist) { + SendBirdAction.getInstance() + .getChannel(element.id, false) + .then(channel => { + this.updateItem(channel); + }) + .catch(error => { + errorAlert(error.message); + }); + } else { + if (isFirst) { + appendToFirst(this.groupChannelList, element); + } else { + this.groupChannelList.appendChild(element); + } + } + LeftListItem.updateUnreadCount(); + this.toggleGroupChannelDefaultItem(); + } + + removeGroupChannelItem(elementId) { + const removeEl = this.getItem(elementId); + if (removeEl) { + this.groupChannelList.removeChild(removeEl); + } + this.toggleGroupChannelDefaultItem(); + } + + clear() { + const openItems = this.openChannelList.getElementsByClassName(LeftListItem.getItemRootClassName()); + const groupItems = this.groupChannelList.getElementsByClassName(LeftListItem.getItemRootClassName()); + const removeItems = [...openItems, ...groupItems]; + for (let i = 0; i < removeItems.length; i++) { + removeItems[i].parentNode.removeChild(removeItems[i]); + } + this.toggleOpenChannelDefaultItem(); + this.toggleGroupChannelDefaultItem(); + } + + static getInstance() { + return new ChatLeftMenu(); + } +} + +export { ChatLeftMenu }; diff --git a/javascript/javascript-basic/src/js/SendBirdAction.js b/javascript/javascript-basic/src/js/SendBirdAction.js new file mode 100644 index 00000000..d57278f7 --- /dev/null +++ b/javascript/javascript-basic/src/js/SendBirdAction.js @@ -0,0 +1,392 @@ +import SendBird from 'sendbird'; +import { + APP_ID as appId +} from './const'; +import { + isNull +} from './utils'; + +let instance = null; + +class SendBirdAction { + constructor() { + if (instance) { + return instance; + } + this.sb = new SendBird({ + appId + }); + this.userQuery = null; + this.openChannelQuery = null; + this.groupChannelQuery = null; + this.previousMessageQuery = null; + this.participantQuery = null; + this.blockedQuery = null; + instance = this; + } + + /** + * Connect + */ + connect(userId, nickname) { + return new Promise((resolve, reject) => { + const sb = SendBird.getInstance(); + sb.connect( + userId, + (user, error) => { + if (error) { + reject(error); + } else { + sb.updateCurrentUserInfo(decodeURIComponent(nickname), null, (user, error) => { + error ? reject(error) : resolve(user); + }); + } + } + ); + }); + } + + disconnect() { + return new Promise((resolve, reject) => { + this.sb.disconnect((response, error) => { + error ? reject(error) : resolve(); + }); + }); + } + + /** + * User + */ + getCurrentUser() { + return this.sb.currentUser; + } + + /** + * + * #################### SECURITY TIPS #################### + * Before launching, you should review "Allow retrieving user list from SDK" under ⚙️ Sendbird Dashboard ->Settings -> Security. + * It's turned on at first to simplify running samples and implementing your first code. + * Most apps will want to disable "Allow retrieving user list from SDK" as that could possibly expose user information + * #################### SECURITY TIPS #################### + * + */ + getUserList(isInit = false) { + if (isInit || isNull(this.userQuery)) { + this.userQuery = this.sb.createApplicationUserListQuery(); + this.userQuery.limit = 30; + } + return new Promise((resolve, reject) => { + if (this.userQuery.hasNext && !this.userQuery.isLoading) { + this.userQuery.next((list, error) => { + error ? reject(error) : resolve(list); + }); + } else { + resolve([]); + } + }); + } + + isCurrentUser(user) { + return user.userId === this.sb.currentUser.userId; + } + + getBlockedList(isInit = false) { + if (isInit || isNull(this.blockedQuery)) { + this.blockedQuery = this.sb.createBlockedUserListQuery(); + this.blockedQuery.limit = 30; + } + return new Promise((resolve, reject) => { + if (this.blockedQuery.hasNext && !this.blockedQuery.isLoading) { + this.blockedQuery.next((blockedList, error) => { + error ? reject(error) : resolve(blockedList); + }); + } else { + resolve([]); + } + }); + } + + blockUser(user, isBlock = true) { + return new Promise((resolve, reject) => { + if (isBlock) { + this.sb.blockUser(user, (response, error) => { + error ? reject(error) : resolve(); + }); + } else { + this.sb.unblockUser(user, (response, error) => { + error ? reject(error) : resolve(); + }); + } + }); + } + + /** + * Channel + */ + getChannel(channelUrl, isOpenChannel = true) { + return new Promise((resolve, reject) => { + if (isOpenChannel) { + this.sb.OpenChannel.getChannel(channelUrl, (openChannel, error) => { + error ? reject(error) : resolve(openChannel); + }); + } else { + this.sb.GroupChannel.getChannel(channelUrl, (groupChannel, error) => { + error ? reject(error) : resolve(groupChannel); + }); + } + }); + } + + /** + * Open Channel + */ + getOpenChannelList(isInit = false, urlKeyword = '') { + if (isInit || isNull(this.openChannelQuery)) { + this.openChannelQuery = this.sb.OpenChannel.createOpenChannelListQuery(); + this.openChannelQuery.limit = 20; + this.openChannelQuery.urlKeyword = urlKeyword; + } + return new Promise((resolve, reject) => { + if (this.openChannelQuery.hasNext && !this.openChannelQuery.isLoading) { + this.openChannelQuery.next((list, error) => { + error ? reject(error) : resolve(list); + }); + } else { + resolve([]); + } + }); + } + + /** + * + * #################### SECURITY TIPS #################### + * Before launching, you should review "Allow creating open channels from SDK" under ⚙️ Sendbird Dashboard -> Settings -> Security. + * It's turned on at first to simplify running samples and implementing your first code. + * Most apps will want to disable "Allow creating open channels from SDK" as that could cause unwanted operations + * #################### SECURITY TIPS #################### + * + */ + createOpenChannel(channelName) { + return new Promise((resolve, reject) => { + channelName + ? + this.sb.OpenChannel.createChannel(channelName, null, null, (openChannel, error) => { + error ? reject(error) : resolve(openChannel); + }) : + this.sb.OpenChannel.createChannel((openChannel, error) => { + error ? reject(error) : resolve(openChannel); + }); + }); + } + + enter(channelUrl) { + return new Promise((resolve, reject) => { + this.sb.OpenChannel.getChannel(channelUrl, (openChannel, error) => { + if (error) { + reject(error); + } else { + openChannel.enter((response, error) => { + error ? reject(error) : resolve(); + }); + } + }); + }); + } + + exit(channelUrl) { + return new Promise((resolve, reject) => { + this.sb.OpenChannel.getChannel(channelUrl, (openChannel, error) => { + if (error) { + reject(error); + } else { + openChannel.exit((response, error) => { + error ? reject(error) : resolve(); + }); + } + }); + }); + } + + getParticipantList(channelUrl, isInit = false) { + return new Promise((resolve, reject) => { + this.sb.OpenChannel.getChannel(channelUrl, (openChannel, error) => { + if (error) { + reject(error); + } else { + if (isInit || isNull(this.participantQuery)) { + this.participantQuery = openChannel.createParticipantListQuery(); + this.participantQuery.limit = 30; + } + if (this.participantQuery.hasNext && !this.participantQuery.isLoading) { + this.participantQuery.next((participantList, error) => { + error ? reject(error) : resolve(participantList); + }); + } else { + resolve([]); + } + } + }); + }); + } + + /** + * Group Channel + */ + getGroupChannelList(isInit = false) { + if (isInit || isNull(this.groupChannelQuery)) { + this.groupChannelQuery = this.sb.GroupChannel.createMyGroupChannelListQuery(); + this.groupChannelQuery.limit = 50; + this.groupChannelQuery.includeEmpty = false; + this.groupChannelQuery.order = 'latest_last_message'; + } + return new Promise((resolve, reject) => { + if (this.groupChannelQuery.hasNext && !this.groupChannelQuery.isLoading) { + this.groupChannelQuery.next((list, error) => { + error ? reject(error) : resolve(list); + }); + } else { + resolve([]); + } + }); + } + + /** + * + * #################### SECURITY TIPS #################### + * Before launching, you should review "Allow creating group channels from SDK" under ⚙️ Sendbird Dashboard -> Settings -> Security. + * It's turned on at first to simplify running samples and implementing your first code. + * Most apps will want to disable "Allow creating group channels from SDK" as that could cause unwanted operations. + * #################### SECURITY TIPS #################### + * + */ + createGroupChannel(userIds) { + return new Promise((resolve, reject) => { + let params = new this.sb.GroupChannelParams(); + params.addUserIds(userIds); + this.sb.GroupChannel.createChannel(params, (groupChannel, error) => { + error ? reject(error) : resolve(groupChannel); + }); + }); + } + + inviteGroupChannel(channelUrl, userIds) { + return new Promise((resolve, reject) => { + this.sb.GroupChannel.getChannel(channelUrl, (groupChannel, error) => { + if (error) { + reject(error); + } else { + groupChannel.inviteWithUserIds(userIds, (groupChannel, error) => { + error ? reject(error) : resolve(groupChannel); + }); + } + }); + }); + } + + leave(channelUrl) { + return new Promise((resolve, reject) => { + this.sb.GroupChannel.getChannel(channelUrl, (groupChannel, error) => { + if (error) { + reject(error); + } else { + groupChannel.leave((response, error) => { + error ? reject(error) : resolve(); + }); + } + }); + }); + } + + hide(channelUrl) { + return new Promise((resolve, reject) => { + this.sb.GroupChannel.getChannel(channelUrl, (groupChannel, error) => { + if (error) { + reject(error); + } else { + groupChannel.hide((response, error) => { + error ? reject(error) : resolve(); + }); + } + }); + }); + } + + markAsRead(channel) { + channel.markAsRead(); + } + + /** + * Message + */ + getMessageList(channel, isInit = false) { + if (isInit || isNull(this.previousMessageQuery)) { + this.previousMessageQuery = channel.createPreviousMessageListQuery(); + } + return new Promise((resolve, reject) => { + if (this.previousMessageQuery.hasMore && !this.previousMessageQuery.isLoading) { + this.previousMessageQuery.load(50, false, (messageList, error) => { + error ? reject(error) : resolve(messageList); + }); + } else { + resolve([]); + } + }); + } + + getReadReceipt(channel, message) { + if (this.isCurrentUser(message.sender)) { + return channel.getReadReceipt(message); + } else { + return 0; + } + } + + sendUserMessage({ + channel, + message, + handler + }) { + return channel.sendUserMessage(message, (message, error) => { + if (handler) handler(message, error); + }); + } + + sendFileMessage({ + channel, + file, + thumbnailSizes, + handler + }) { + const fileMessageParams = new this.sb.FileMessageParams(); + fileMessageParams.file = file; + fileMessageParams.thumbnailSizes = thumbnailSizes; + + return channel.sendFileMessage(fileMessageParams, (message, error) => { + if (handler) handler(message, error); + }); + } + + deleteMessage({ + channel, + message + }) { + return new Promise((resolve, reject) => { + if (!this.isCurrentUser(message.sender)) { + reject({ + message: 'You have not ownership in this message.' + }); + } + channel.deleteMessage(message, (response, error) => { + error ? reject(error) : resolve(response); + }); + }); + } + + static getInstance() { + return new SendBirdAction(); + } +} + +export { + SendBirdAction +}; diff --git a/javascript/javascript-basic/src/js/SendBirdChatEvent.js b/javascript/javascript-basic/src/js/SendBirdChatEvent.js new file mode 100644 index 00000000..16e2fb95 --- /dev/null +++ b/javascript/javascript-basic/src/js/SendBirdChatEvent.js @@ -0,0 +1,68 @@ +import SendBird from 'sendbird'; +import { uuid4 } from './utils'; + +let instance = null; + +class SendBirdChatEvent { + constructor() { + if (instance) { + return instance; + } + + this.sb = SendBird.getInstance(); + this.key = uuid4(); + this._createChannelHandler(); + + this.onMessageReceived = null; + this.onMessageUpdated = null; + this.onMessageDeleted = null; + + this.onReadReceiptUpdated = null; + this.onTypingStatusUpdated = null; + instance = this; + } + + /** + * Channel Handler + */ + _createChannelHandler() { + const handler = new this.sb.ChannelHandler(); + handler.onMessageReceived = (channel, message) => { + if (this.onMessageReceived) { + this.onMessageReceived(channel, message); + } + }; + handler.onMessageUpdated = (channel, message) => { + if (this.onMessageUpdated) { + this.onMessageUpdated(channel, message); + } + }; + handler.onMessageDeleted = (channel, messageId) => { + if (this.onMessageDeleted) { + this.onMessageDeleted(channel, messageId); + } + }; + + handler.onReadReceiptUpdated = groupChannel => { + if (this.onReadReceiptUpdated) { + this.onReadReceiptUpdated(groupChannel); + } + }; + handler.onTypingStatusUpdated = groupChannel => { + if (this.onTypingStatusUpdated) { + this.onTypingStatusUpdated(groupChannel); + } + }; + this.sb.addChannelHandler(this.key, handler); + } + + remove() { + this.sb.removeChannelHandler(this.key); + } + + static getInstance() { + return instance; + } +} + +export { SendBirdChatEvent }; diff --git a/javascript/javascript-basic/src/js/SendBirdConnection.js b/javascript/javascript-basic/src/js/SendBirdConnection.js new file mode 100644 index 00000000..c335f638 --- /dev/null +++ b/javascript/javascript-basic/src/js/SendBirdConnection.js @@ -0,0 +1,53 @@ +import SendBird from 'sendbird'; +import { uuid4 } from './utils'; + +let instance = null; + +class SendBirdConnection { + constructor() { + if (instance) { + return instance; + } + + this.sb = SendBird.getInstance(); + this.key = uuid4(); + this.channel = null; + this._createConnectionHandler(this.key); + + this.onReconnectStarted = null; + this.onReconnectSucceeded = null; + this.onReconnectFailed = null; + + instance = this; + } + + _createConnectionHandler(key) { + const handler = new this.sb.ConnectionHandler(); + handler.onReconnectStarted = () => { + if (this.onReconnectStarted) { + this.onReconnectStarted(); + } + }; + handler.onReconnectSucceeded = () => { + if (this.onReconnectSucceeded) { + this.onReconnectSucceeded(); + } + }; + handler.onReconnectFailed = () => { + if (this.onReconnectFailed) { + this.onReconnectFailed(); + } + }; + this.sb.addConnectionHandler(key, handler); + } + + remove() { + this.sb.removeConnectionHandler(this.key); + } + + static getInstance() { + return new SendBirdConnection(); + } +} + +export { SendBirdConnection }; diff --git a/javascript/javascript-basic/src/js/SendBirdEvent.js b/javascript/javascript-basic/src/js/SendBirdEvent.js new file mode 100644 index 00000000..19996ea7 --- /dev/null +++ b/javascript/javascript-basic/src/js/SendBirdEvent.js @@ -0,0 +1,52 @@ +import SendBird from 'sendbird'; +import { uuid4 } from './utils'; + +class SendBirdEvent { + constructor() { + this.sb = SendBird.getInstance(); + this.key = uuid4(); + this._createChannelHandler(); + + this.onChannelChanged = null; + this.onUserJoined = null; + this.onUserLeft = null; + this.onChannelHidden = null; + this.onUserEntered = null; + } + + _createChannelHandler() { + const handler = new this.sb.ChannelHandler(); + handler.onChannelChanged = channel => { + if (this.onChannelChanged) { + this.onChannelChanged(channel); + } + }; + handler.onUserJoined = (groupChannel, user) => { + if (this.onUserJoined) { + this.onUserJoined(groupChannel, user); + } + }; + handler.onUserLeft = (groupChannel, user) => { + if (this.onUserLeft) { + this.onUserLeft(groupChannel, user); + } + }; + handler.onChannelHidden = groupChannel => { + if (this.onChannelHidden) { + this.onChannelHidden(groupChannel); + } + }; + handler.onUserEntered = (openChannel, user) => { + if (this.onUserEntered) { + this.onUserEntered(openChannel, user); + } + }; + this.sb.addChannelHandler(this.key, handler); + } + + remove() { + this.sb.removeChannelHandler(this.key); + } +} + +export { SendBirdEvent }; diff --git a/javascript/javascript-basic/src/js/components/ChatBody.js b/javascript/javascript-basic/src/js/components/ChatBody.js new file mode 100644 index 00000000..1089d043 --- /dev/null +++ b/javascript/javascript-basic/src/js/components/ChatBody.js @@ -0,0 +1,143 @@ +import styles from '../../scss/chat-body.scss'; +import { appendToFirst, createDivEl, errorAlert, getDataInElement, isScrollBottom, removeClass } from '../utils'; +import { Message } from './Message'; +import { SendBirdAction } from '../SendBirdAction'; +import { Spinner } from './Spinner'; +import { MESSAGE_REQ_ID } from '../const'; + +class ChatBody { + constructor(channel) { + this.channel = channel; + this.readReceiptManageList = []; + this.scrollHeight = 0; + this.element = this._createElement(); + } + + _createElement() { + const root = createDivEl({ className: styles['chat-body'] }); + root.addEventListener('scroll', () => { + if (root.scrollTop === 0) { + Spinner.start(root); + this.updateCurrentScrollHeight(); + SendBirdAction.getInstance() + .getMessageList(this.channel) + .then(messageList => { + messageList.reverse(); + this.renderMessages(messageList, false, true); + Spinner.remove(); + }) + .catch(error => { + errorAlert(error.message); + }); + } + }); + return root; + } + + scrollToBottom() { + this.element.scrollTop = this.element.scrollHeight - this.element.offsetHeight; + } + + updateCurrentScrollHeight() { + this.scrollHeight = this.element.scrollHeight; + } + + repositionScroll(imageOffsetHeight) { + this.element.scrollTop += imageOffsetHeight; + } + + updateReadReceipt() { + this.readReceiptManageList.forEach(message => { + if (message.messageId.toString() !== '0') { + const className = Message.getReadReceiptElementClassName(); + const messageItem = this._getItem(message.messageId, false); + if (messageItem) { + let readItem = null; + try { + readItem = messageItem.getElementsByClassName(className)[0]; + } catch (e) { + readItem = null; + } + const latestCount = SendBirdAction.getInstance().getReadReceipt(this.channel, message); + if (readItem && latestCount.toString() !== readItem.textContent.toString()) { + readItem.innerHTML = latestCount; + if (latestCount.toString() === '0') { + removeClass(readItem, className); + } + } + } + } + }); + } + + readReceiptManage(message) { + for (let i = 0; i < this.readReceiptManageList.length; i++) { + if (message.reqId) { + if (this.readReceiptManageList[i].reqId === message.reqId) { + this.readReceiptManageList.splice(i, 1); + break; + } + } else { + if (this.readReceiptManageList[i].messageId === message.messageId) { + this.readReceiptManageList.splice(i, 1); + break; + } + } + } + this.readReceiptManageList.push(message); + this.updateReadReceipt(); + } + + _getItem(messageId, isRequestId = false) { + const items = this.element.childNodes; + for (let i = 0; i < items.length; i++) { + const elementId = isRequestId ? getDataInElement(items[i], MESSAGE_REQ_ID) : items[i].id; + if (elementId === messageId.toString()) { + return items[i]; + } + } + return null; + } + + renderMessages(messageList, goToBottom = true, isPastMessage = false) { + messageList.forEach(message => { + const messageItem = new Message({ channel: this.channel, message }); + const requestId = getDataInElement(messageItem.element, MESSAGE_REQ_ID) + ? getDataInElement(messageItem.element, MESSAGE_REQ_ID) + : '-1'; + const requestItem = this._getItem(requestId, true); + const existItem = this._getItem(messageItem.element.id, false); + if (requestItem || existItem) { + this.element.replaceChild(messageItem.element, requestItem ? requestItem : existItem); + } else { + if (isPastMessage) { + appendToFirst(this.element, messageItem.element); + this.element.scrollTop = this.element.scrollHeight - this.scrollHeight; + } else { + const isBottom = isScrollBottom(this.element); + this.element.appendChild(messageItem.element); + if (isBottom) { + this.scrollToBottom(); + } + } + } + if ( + (message.isUserMessage() || message.isFileMessage()) && + SendBirdAction.getInstance().isCurrentUser(message.sender) && + this.channel.isGroupChannel() + ) { + this.readReceiptManage(message); + } + }); + if (goToBottom) this.scrollToBottom(); + } + + removeMessage(messageId, isRequestId = false) { + const removeElement = this._getItem(messageId, isRequestId); + if (removeElement) { + this.element.removeChild(removeElement); + } + } +} + +export { ChatBody }; diff --git a/javascript/javascript-basic/src/js/components/ChatInput.js b/javascript/javascript-basic/src/js/components/ChatInput.js new file mode 100644 index 00000000..caa2d065 --- /dev/null +++ b/javascript/javascript-basic/src/js/components/ChatInput.js @@ -0,0 +1,127 @@ +import styles from '../../scss/chat-input.scss'; +import { createDivEl, protectFromXSS } from '../utils'; +import { DISPLAY_BLOCK, DISPLAY_NONE, FILE_ID, KEY_ENTER } from '../const'; +import { SendBirdAction } from '../SendBirdAction'; +import { Chat } from '../Chat'; + +class ChatInput { + constructor(channel) { + this.channel = channel; + this.input = null; + this.typing = null; + this.element = this._createElement(channel); + } + + _createElement(channel) { + const root = createDivEl({ className: styles['chat-input'] }); + + this.typing = createDivEl({ className: styles['typing-field'] }); + root.appendChild(this.typing); + + const file = document.createElement('label'); + file.className = styles['input-file']; + file.for = FILE_ID; + file.addEventListener('click', () => { + if (this.channel.isGroupChannel()) { + SendBirdAction.getInstance().markAsRead(this.channel); + } + }); + + const fileInput = document.createElement('input'); + fileInput.type = 'file'; + fileInput.id = FILE_ID; + fileInput.style.display = DISPLAY_NONE; + fileInput.addEventListener('change', () => { + const sendFile = fileInput.files[0]; + if (sendFile) { + const tempMessage = SendBirdAction.getInstance().sendFileMessage({ + channel: this.channel, + file: sendFile, + handler: (message, error) => { + error + ? Chat.getInstance().main.removeMessage(tempMessage.reqId, true) + : Chat.getInstance().main.renderMessages([message]); + } + }); + Chat.getInstance().main.renderMessages([tempMessage]); + } + }); + + file.appendChild(fileInput); + root.appendChild(file); + + const inputText = createDivEl({ className: styles['input-text'] }); + + this.input = document.createElement('textarea'); + this.input.className = styles['input-text-area']; + this.input.placeholder = 'Write a chat...'; + this.input.addEventListener('click', () => { + if (this.channel.isGroupChannel()) { + SendBirdAction.getInstance().markAsRead(this.channel); + } + }); + this.input.addEventListener('keypress', e => { + if (e.keyCode === KEY_ENTER) { + if (!e.shiftKey) { + e.preventDefault(); + const message = this.input.value; + this.input.value = ''; + if (message) { + const tempMessage = SendBirdAction.getInstance().sendUserMessage({ + channel: this.channel, + message, + handler: (message, error) => { + error + ? Chat.getInstance().main.removeMessage(tempMessage.reqId, true) + : Chat.getInstance().main.renderMessages([message]); + } + }); + Chat.getInstance().main.renderMessages([tempMessage]); + if (channel.isGroupChannel()) { + channel.endTyping(); + } + } + } else { + if (channel.isGroupChannel()) { + channel.startTyping(); + } + } + } else { + if (channel.isGroupChannel()) { + channel.startTyping(); + } + } + }); + this.input.addEventListener('focusin', () => { + this.channel._autoMarkAsRead = true; + inputText.style.border = '1px solid #2C2D30'; + }); + this.input.addEventListener('focusout', () => { + this.channel._autoMarkAsRead = false; + inputText.style.border = ''; + }); + + inputText.appendChild(this.input); + root.appendChild(inputText); + return root; + } + + updateTyping(memberList) { + let nicknames = ''; + if (memberList.length === 1) { + nicknames = `${protectFromXSS(memberList[0].nickname)} is`; + } else if (memberList.length === 2) { + nicknames = `${memberList + .map(member => { + return protectFromXSS(member.nickname); + }) + .join(', ')} are`; + } else if (memberList.length !== 0) { + nicknames = 'Several are'; + } + this.typing.style.display = nicknames ? DISPLAY_BLOCK : DISPLAY_NONE; + this.typing.innerHTML = `${nicknames} typing...`; + } +} + +export { ChatInput }; diff --git a/javascript/javascript-basic/src/js/components/ChatMain.js b/javascript/javascript-basic/src/js/components/ChatMain.js new file mode 100644 index 00000000..d06d0082 --- /dev/null +++ b/javascript/javascript-basic/src/js/components/ChatMain.js @@ -0,0 +1,64 @@ +import styles from '../../scss/chat-main.scss'; +import { ChatBody } from './ChatBody'; +import { ChatInput } from './ChatInput'; +import { Chat } from '../Chat'; +import { createDivEl } from '../utils'; +import { ChatMenu } from './ChatMenu'; + +class ChatMain { + constructor(channel) { + this.channel = channel; + this.body = null; + this.input = null; + this.menu = null; + this._create(); + } + + _create() { + const root = createDivEl({ className: styles['chat-main-root'] }); + + const main = createDivEl({ className: styles['chat-main'] }); + root.appendChild(main); + + this.body = new ChatBody(this.channel); + main.appendChild(this.body.element); + + this.input = new ChatInput(this.channel); + main.appendChild(this.input.element); + + this.menu = new ChatMenu(this.channel); + root.appendChild(this.menu.element); + + Chat.getInstance().element.appendChild(root); + } + + renderMessages(messageList, goToBottom = true, isPastMessage = false) { + this.body.renderMessages(messageList, goToBottom, isPastMessage); + } + + removeMessage(messageId, isRequestId = false) { + this.body.removeMessage(messageId, isRequestId); + } + + updateReadReceipt() { + this.body.updateReadReceipt(); + } + + updateTyping(memberList) { + this.input.updateTyping(memberList); + } + + repositionScroll(height) { + this.body.repositionScroll(height); + } + + updateBlockedList(user, isBlock) { + this.menu.updateBlockedList(user, isBlock); + } + + updateMenu(channel) { + this.menu.updateMenu(channel); + } +} + +export { ChatMain }; diff --git a/javascript/javascript-basic/src/js/components/ChatMenu.js b/javascript/javascript-basic/src/js/components/ChatMenu.js new file mode 100644 index 00000000..a1528be6 --- /dev/null +++ b/javascript/javascript-basic/src/js/components/ChatMenu.js @@ -0,0 +1,185 @@ +import styles from '../../scss/chat-menu.scss'; +import { appendToFirst, createDivEl, errorAlert, isScrollBottom } from '../utils'; +import { DISPLAY_FLEX, DISPLAY_NONE } from '../const'; +import { Spinner } from './Spinner'; +import { ChatUserItem } from './ChatUserItem'; +import { SendBirdAction } from '../SendBirdAction'; + +const Type = { + PARTICIPANTS: 'PARTICIPANTS', + MEMBERS: 'MEMBERS', + BLOCKED: 'BLOCKED' +}; + +class ChatMenu { + constructor(channel) { + this.channel = channel; + this.element = createDivEl({ className: styles['chat-menu-root'] }); + this.listElement = null; + this.type = null; + this._createListElement(); + this._createElement(); + } + + _createListElement() { + this.listElement = createDivEl({ className: styles['menu-list'] }); + + const title = createDivEl({ className: styles['list-title'] }); + title.addEventListener('click', () => { + this.type = null; + this.list.innerHTML = ''; + this.listElement.style.display = DISPLAY_NONE; + }); + this.listElement.appendChild(title); + const backBtn = createDivEl({ className: styles['list-back'] }); + title.appendChild(backBtn); + this.titleText = createDivEl({ className: styles['list-text'] }); + title.appendChild(this.titleText); + + this.list = createDivEl({ className: styles['list-body'] }); + this.list.addEventListener('scroll', () => { + if (this.type === Type.PARTICIPANTS) { + if (isScrollBottom(this.list)) { + this._getParticipantList(this.type); + } + } else if (this.type === Type.BLOCKED) { + this._getBlockedList(this.type); + } + }); + this.listElement.appendChild(this.list); + + this.element.appendChild(this.listElement); + } + + _createElement() { + const usersItem = createDivEl({ className: styles['menu-item'] }); + const users = createDivEl({ + className: styles['menu-users'], + content: this.channel.isOpenChannel() ? Type.PARTICIPANTS : Type.MEMBERS + }); + usersItem.appendChild(users); + const arrowUser = createDivEl({ className: styles['menu-arrow'] }); + usersItem.appendChild(arrowUser); + usersItem.addEventListener('click', () => { + this._renderList(users.textContent); + }); + this.element.appendChild(usersItem); + + const blockedItem = createDivEl({ className: styles['menu-item'] }); + const blocked = createDivEl({ className: styles['menu-blocked'], content: Type.BLOCKED }); + blockedItem.appendChild(blocked); + const arrowBlocked = createDivEl({ className: styles['menu-arrow'] }); + blockedItem.appendChild(arrowBlocked); + blockedItem.addEventListener('click', () => { + this._renderList(blocked.textContent); + }); + this.element.appendChild(blockedItem); + } + + _renderList(listTitle) { + switch (listTitle) { + case Type.PARTICIPANTS: + this.type = Type.PARTICIPANTS; + this._getParticipantList(listTitle, true); + break; + case Type.MEMBERS: + this.type = Type.MEMBERS; + this._getMemberList(listTitle); + break; + case Type.BLOCKED: + this.type = Type.BLOCKED; + this._getBlockedList(listTitle, true); + break; + default: + this.titleText.innerHTML = ''; + break; + } + } + + _getParticipantList(listTitle, isInit = false) { + if (this.channel.isOpenChannel()) { + Spinner.start(this.listElement); + if (isInit) { + this.titleText.innerHTML = listTitle; + this.listElement.style.display = DISPLAY_FLEX; + } + SendBirdAction.getInstance() + .getParticipantList(this.channel.url, isInit) + .then(participantList => { + participantList.forEach(user => { + const participantItem = new ChatUserItem({ user, hasEvent: false }); + this.list.appendChild(participantItem.element); + }); + Spinner.remove(); + }) + .catch(error => { + errorAlert(error.message); + }); + } + } + + _getMemberList(listTitle) { + if (this.channel.isGroupChannel()) { + Spinner.start(this.listElement); + this.list.innerHTML = ''; + this.titleText.innerHTML = listTitle; + this.listElement.style.display = DISPLAY_FLEX; + this.channel.members.forEach(user => { + const memberItem = new ChatUserItem({ user, hasEvent: false }); + this.list.appendChild(memberItem.element); + }); + Spinner.remove(); + } + } + + _getBlockedList(listTitle, isInit = false) { + Spinner.start(this.listElement); + if (isInit) { + this.list.innerHTML = ''; + this.titleText.innerHTML = listTitle; + this.listElement.style.display = DISPLAY_FLEX; + } + SendBirdAction.getInstance() + .getBlockedList(isInit) + .then(blockedList => { + blockedList.forEach(user => { + const blockedItem = new ChatUserItem({ user, hasEvent: true }); + this.list.appendChild(blockedItem.element); + }); + Spinner.remove(); + }) + .catch(error => { + errorAlert(error.message); + }); + } + + updateBlockedList(user, isBlock) { + if (this.list) { + if (isBlock) { + const blockedItem = new ChatUserItem({ user, hasEvent: true }); + appendToFirst(this.list, blockedItem.element); + } else { + const items = this.list.childNodes; + for (let i = 0; i < items.length; i++) { + if (items[0].id === user.userId) { + this.list.removeChild(items[0]); + break; + } + } + } + } + } + + updateMenu(channel) { + if (this.type === Type.MEMBERS) { + this.channel = channel; + this._getMemberList(this.type); + } + } + + static get Type() { + return Type; + } +} + +export { ChatMenu }; diff --git a/javascript/javascript-basic/src/js/components/ChatTopMenu.js b/javascript/javascript-basic/src/js/components/ChatTopMenu.js new file mode 100644 index 00000000..0f692d3f --- /dev/null +++ b/javascript/javascript-basic/src/js/components/ChatTopMenu.js @@ -0,0 +1,94 @@ +import styles from '../../scss/chat-top-menu.scss'; +import { createDivEl, errorAlert, protectFromXSS } from '../utils'; +import { Chat } from '../Chat'; +import { ChatLeftMenu } from '../ChatLeftMenu'; +import { UserList } from './UserList'; +import { SendBirdAction } from '../SendBirdAction'; + +class ChatTopMenu { + constructor(channel) { + this.channel = channel; + this.element = this._createElement(channel); + } + + get chatTitle() { + const isOpenChannel = this.channel.isOpenChannel(); + if (isOpenChannel) { + return `# ${this.channel.name}`; + } else { + return this.channel.members + .map(member => { + return protectFromXSS(member.nickname); + }) + .join(', '); + } + } + + _createElement(channel) { + const isOpenChannel = channel.isOpenChannel(); + + const root = createDivEl({ className: styles['chat-top'] }); + + this.title = createDivEl({ + className: isOpenChannel ? styles['chat-title'] : [styles['chat-title'], styles['is-group']], + content: this.chatTitle + }); + root.appendChild(this.title); + + const button = createDivEl({ className: styles['chat-button'] }); + if (!isOpenChannel) { + const invite = createDivEl({ className: styles['button-invite'] }); + invite.addEventListener('click', () => { + UserList.getInstance().render(true); + }); + button.appendChild(invite); + const hide = createDivEl({ className: styles['button-hide'] }); + hide.addEventListener('click', () => { + SendBirdAction.getInstance() + .hide(channel.url) + .then(() => { + ChatLeftMenu.getInstance().removeGroupChannelItem(this.channel.url); + Chat.getInstance().renderEmptyElement(); + }) + .catch(error => { + errorAlert(error.message); + }); + }); + button.appendChild(hide); + } + const leave = createDivEl({ className: styles['button-leave'] }); + leave.addEventListener('click', () => { + if (isOpenChannel) { + ChatLeftMenu.getInstance().removeOpenChannelItem(this.channel.url); + SendBirdAction.getInstance() + .exit(channel.url) + .then(() => { + Chat.getInstance().renderEmptyElement(); + }) + .catch(error => { + errorAlert(error.message); + }); + } else { + SendBirdAction.getInstance() + .leave(channel.url) + .then(() => { + ChatLeftMenu.getInstance().removeGroupChannelItem(this.channel.url); + Chat.getInstance().renderEmptyElement(); + }) + .catch(error => { + errorAlert(error.message); + }); + } + }); + button.appendChild(leave); + root.appendChild(button); + return root; + } + + updateTitle(channel) { + this.channel = channel; + this.title.innerHTML = this.chatTitle; + } +} + +export { ChatTopMenu }; diff --git a/javascript/javascript-basic/src/js/components/ChatUserItem.js b/javascript/javascript-basic/src/js/components/ChatUserItem.js new file mode 100644 index 00000000..fcc51d66 --- /dev/null +++ b/javascript/javascript-basic/src/js/components/ChatUserItem.js @@ -0,0 +1,49 @@ +import styles from '../../scss/chat-user-item.scss'; +import { createDivEl, protectFromXSS } from '../utils'; +import { COLOR_RED } from '../const'; +import { UserBlockModal } from './UserBlockModal'; +import { SendBirdAction } from '../SendBirdAction'; + +class ChatUserItem { + constructor({ user, hasEvent }) { + this.user = user; + this.hasEvent = hasEvent; + this.element = null; + this._create(); + } + + _create() { + this.element = createDivEl({ className: styles['chat-user-item'], id: this.user.userId }); + if (this.hasEvent) { + this.element.addEventListener('mouseover', () => { + this._hoverOnUser(this.user.nickname, true); + }); + this.element.addEventListener('mouseleave', () => { + this._hoverOnUser(this.user.nickname, false); + }); + this.element.addEventListener('click', () => { + const userBlockModal = new UserBlockModal({ user: this.user, isBlock: false }); + userBlockModal.render(); + }); + } + + const image = createDivEl({ className: styles['user-image'], background: protectFromXSS(this.user.profileUrl) }); + this.element.appendChild(image); + + this.nickname = createDivEl({ + className: SendBirdAction.getInstance().isCurrentUser(this.user) + ? [styles['user-nickname'], styles['is-user']] + : styles['user-nickname'], + content: protectFromXSS(this.user.nickname) + }); + this.element.appendChild(this.nickname); + } + + _hoverOnUser(nickname, hover) { + this.nickname.innerHTML = hover ? 'UNBLOCK' : protectFromXSS(nickname); + this.nickname.style.color = hover ? COLOR_RED : ''; + this.nickname.style.opacity = hover ? '1' : ''; + } +} + +export { ChatUserItem }; diff --git a/javascript/javascript-basic/src/js/components/LeftListItem.js b/javascript/javascript-basic/src/js/components/LeftListItem.js new file mode 100644 index 00000000..38d27277 --- /dev/null +++ b/javascript/javascript-basic/src/js/components/LeftListItem.js @@ -0,0 +1,147 @@ +import styles from '../../scss/list-item.scss'; +import { + addClass, + createDivEl, + getDataInElement, + protectFromXSS, + removeClass, + setDataInElement, + timestampFromNow +} from '../utils'; +import { ChatLeftMenu } from '../ChatLeftMenu'; + +const KEY_MESSAGE_LAST_TIME = 'origin'; + +class LeftListItem { + constructor({ channel, handler }) { + this.channel = channel; + this.element = this._createElement(handler); + } + + get channelUrl() { + return this.channel.url; + } + + get title() { + return this.channel.isOpenChannel() + ? `# ${this.channel.name}` + : this.channel.members + .map(member => { + return protectFromXSS(member.nickname); + }) + .join(', '); + } + + get lastMessagetime() { + if (this.channel.isOpenChannel() || !this.channel.lastMessage) { + return 0; + } else { + return this.channel.lastMessage.createdAt; + } + } + + get lastMessageTimeText() { + if (this.channel.isOpenChannel() || !this.channel.lastMessage) { + return 0; + } else { + return LeftListItem.getTimeFromNow(this.channel.lastMessage.createdAt); + } + } + + get lastMessageText() { + if (this.channel.isOpenChannel() || !this.channel.lastMessage) { + return ''; + } else { + return this.channel.lastMessage.isFileMessage() + ? protectFromXSS(this.channel.lastMessage.name) + : protectFromXSS(this.channel.lastMessage.message); + } + } + + get memberCount() { + return this.channel.isOpenChannel() ? '#' : this.channel.memberCount; + } + + get unreadMessageCount() { + const count = this.channel.unreadMessageCount > 9 ? '+9' : this.channel.unreadMessageCount.toString(); + return this.channel.isOpenChannel() ? 0 : count; + } + + _createElement(handler) { + const item = createDivEl({ className: styles['list-item'], id: this.channelUrl }); + if (this.channel.isOpenChannel()) { + const itemTop = createDivEl({ className: styles['item-top'] }); + const itemTopTitle = createDivEl({ className: styles['item-title'], content: this.title }); + itemTop.appendChild(itemTopTitle); + item.appendChild(itemTop); + } else { + const itemTop = createDivEl({ className: styles['item-top'] }); + const itemTopCount = createDivEl({ className: styles['item-count'], content: this.memberCount }); + const itemTopTitle = createDivEl({ className: styles['item-title'], content: this.title }); + itemTop.appendChild(itemTopCount); + itemTop.appendChild(itemTopTitle); + item.appendChild(itemTop); + + const itemBottom = createDivEl({ className: styles['item-bottom'] }); + + const itemBottomMessage = createDivEl({ className: styles['item-message'] }); + const itemBottomMessageText = createDivEl({ + className: styles['item-message-text'], + content: this.lastMessageText + }); + itemBottomMessage.appendChild(itemBottomMessageText); + const itemBottomMessageUnread = createDivEl({ + className: [styles['item-message-unread'], styles.active], + content: this.unreadMessageCount + }); + itemBottomMessage.appendChild(itemBottomMessageUnread); + + const itemBottomTime = createDivEl({ className: styles['item-time'], content: this.lastMessageTimeText }); + setDataInElement(itemBottomTime, KEY_MESSAGE_LAST_TIME, this.lastMessagetime); + itemBottom.appendChild(itemBottomMessage); + itemBottom.appendChild(itemBottomTime); + item.appendChild(itemBottom); + } + + item.addEventListener('click', () => { + if (handler) handler(); + }); + return item; + } + + static updateUnreadCount() { + const items = ChatLeftMenu.getInstance().groupChannelList.getElementsByClassName(styles['item-message-unread']); + if (items && items.length > 0) { + Array.prototype.slice.call(items).forEach(targetItemEl => { + const originTs = targetItemEl.textContent; + if (originTs === '0') { + removeClass(targetItemEl, styles.active); + } else { + addClass(targetItemEl, styles.active); + } + }); + } + } + + static updateLastMessageTime() { + const items = ChatLeftMenu.getInstance().groupChannelList.getElementsByClassName(styles['item-time']); + if (items && items.length > 0) { + Array.prototype.slice.call(items).forEach(targetItemEl => { + const originTs = parseInt(getDataInElement(targetItemEl, KEY_MESSAGE_LAST_TIME)); + if (originTs) { + targetItemEl.innerHTML = LeftListItem.getTimeFromNow(originTs); + } + }); + } + } + + static getTimeFromNow(timestamp) { + return timestampFromNow(timestamp); + } + + static getItemRootClassName() { + return styles['list-item']; + } +} + +export { LeftListItem }; diff --git a/javascript/javascript-basic/src/js/components/List.js b/javascript/javascript-basic/src/js/components/List.js new file mode 100644 index 00000000..d22e7b41 --- /dev/null +++ b/javascript/javascript-basic/src/js/components/List.js @@ -0,0 +1,87 @@ +import styles from '../../scss/list.scss'; +import { createDivEl, isScrollBottom } from '../utils'; +import { OpenChannelSearchBox } from './OpenChannelSearchBox'; + +let instance = null; + +class List { + constructor(title, createSearchBox = false) { + if (instance) { + return instance; + } + this.createSearchBox = createSearchBox; + this.element = this._create(title); + this.scrollEventHandler = null; + this.closeEventHandler = null; + this.searchKeyword = ''; + } + + _create(title) { + const root = createDivEl({ className: styles['list-root'] }); + + const listBody = createDivEl({ className: styles['list-body'] }); + root.appendChild(listBody); + + const listTop = createDivEl({ className: styles['list-top'] }); + listBody.appendChild(listTop); + + const listTopTitle = createDivEl({ className: styles['list-title'], content: title }); + listTop.appendChild(listTopTitle); + const listTopButton = createDivEl({ className: styles['list-button'] }); + listTop.appendChild(listTopButton); + const listTopButtonExit = createDivEl({ className: styles['button-exit'] }); + listTopButton.appendChild(listTopButtonExit); + listTopButtonExit.addEventListener('click', () => { + this.searchKeyword = ''; + OpenChannelSearchBox.clearText(); + const listContent = document.querySelector(`.${styles['list-content']}`); + if (this.closeEventHandler) { + this.closeEventHandler(); + } + listContent.innerHTML = ''; + root.parentElement.removeChild(this.element); + }); + this.buttonRootElement = listTopButton; + + if (this.createSearchBox) { + const searchBox = new OpenChannelSearchBox(); + listBody.appendChild(searchBox.element); + } + + const hr = createDivEl({ className: styles['list-hr'] }); + listBody.appendChild(hr); + + const listContent = createDivEl({ className: styles['list-content'] }); + listBody.appendChild(listContent); + listContent.addEventListener('scroll', () => { + if (isScrollBottom(listContent)) { + if (this.scrollEventHandler) { + this.scrollEventHandler(false, this.searchKeyword); + } + } + }); + + return root; + } + + close() { + const btnExit = document.querySelector(`.${styles['button-exit']}`); + if (btnExit) { + document.querySelector(`.${styles['button-exit']}`).click(); + } + } + + getRootElement() { + return document.querySelector(`.${styles['list-root']}`); + } + + getRootClassName() { + return styles['list-root']; + } + + getContentElement() { + return document.querySelector(`.${styles['list-content']}`); + } +} + +export { List }; diff --git a/javascript/javascript-basic/src/js/components/Message.js b/javascript/javascript-basic/src/js/components/Message.js new file mode 100644 index 00000000..16c9e43e --- /dev/null +++ b/javascript/javascript-basic/src/js/components/Message.js @@ -0,0 +1,192 @@ +import styles from '../../scss/message.scss'; +import { createDivEl, isImage, protectFromXSS, setDataInElement, timestampToTime } from '../utils'; +import { SendBirdAction } from '../SendBirdAction'; +import { COLOR_RED, MESSAGE_REQ_ID } from '../const'; +import { MessageDeleteModal } from './MessageDeleteModal'; +import { UserBlockModal } from './UserBlockModal'; +import { Chat } from '../Chat'; + +class Message { + constructor({ channel, message }) { + this.channel = channel; + this.message = message; + this.element = this._createElement(); + } + + _createElement() { + if (this.message.isUserMessage()) { + return this._createUserElement(); + } else if (this.message.isFileMessage()) { + return this._createFileElement(); + } else if (this.message.isAdminMessage()) { + return this._createAdminElement(); + } else { + console.error('Message is invalid data.'); + return null; + } + } + + _hoverOnNickname(nickname, hover) { + if (!SendBirdAction.getInstance().isCurrentUser(this.message.sender)) { + nickname.innerHTML = hover ? 'BLOCK ' : `${protectFromXSS(this.message.sender.nickname)} : `; + nickname.style.color = hover ? COLOR_RED : ''; + nickname.style.opacity = hover ? '1' : ''; + } + } + + _hoverOnTime(time, hover) { + if (SendBirdAction.getInstance().isCurrentUser(this.message.sender)) { + time.innerHTML = hover ? 'DELETE' : timestampToTime(this.message.createdAt); + time.style.color = hover ? COLOR_RED : ''; + time.style.opacity = hover ? '1' : ''; + time.style.fontWeight = hover ? '600' : ''; + } + } + + _createUserElement() { + const sendbirdAction = SendBirdAction.getInstance(); + const isCurrentUser = sendbirdAction.isCurrentUser(this.message.sender); + const root = createDivEl({ className: styles['chat-message'], id: this.message.messageId }); + setDataInElement(root, MESSAGE_REQ_ID, this.message.reqId); + + const messageContent = createDivEl({ className: styles['message-content'] }); + const nickname = createDivEl({ + className: isCurrentUser ? [styles['message-nickname'], styles['is-user']] : styles['message-nickname'], + content: `${protectFromXSS(this.message.sender.nickname)} : ` + }); + nickname.addEventListener('mouseover', () => { + this._hoverOnNickname(nickname, true); + }); + nickname.addEventListener('mouseleave', () => { + this._hoverOnNickname(nickname, false); + }); + nickname.addEventListener('click', () => { + if (!isCurrentUser) { + const userBlockModal = new UserBlockModal({ user: this.message.sender, isBlock: true }); + userBlockModal.render(); + } + }); + messageContent.appendChild(nickname); + + const msg = createDivEl({ className: styles['message-content'], content: protectFromXSS(this.message.message) }); + messageContent.appendChild(msg); + + const time = createDivEl({ + className: isCurrentUser ? [styles.time, styles['is-user']] : styles.time, + content: timestampToTime(this.message.createdAt) + }); + time.addEventListener('mouseover', () => { + this._hoverOnTime(time, true); + }); + time.addEventListener('mouseleave', () => { + this._hoverOnTime(time, false); + }); + time.addEventListener('click', () => { + if (isCurrentUser) { + const messageDeleteModal = new MessageDeleteModal({ + channel: this.channel, + message: this.message + }); + messageDeleteModal.render(); + } + }); + messageContent.appendChild(time); + + if (this.channel.isGroupChannel()) { + const count = sendbirdAction.getReadReceipt(this.channel, this.message); + const read = createDivEl({ + className: count ? [styles.read, styles.active] : styles.read, + content: count + }); + messageContent.appendChild(read); + } + + root.appendChild(messageContent); + return root; + } + + _createFileElement() { + const sendbirdAction = SendBirdAction.getInstance(); + const root = createDivEl({ className: styles['chat-message'], id: this.message.messageId }); + setDataInElement(root, MESSAGE_REQ_ID, this.message.reqId); + + const messageContent = createDivEl({ className: styles['message-content'] }); + const nickname = createDivEl({ + className: sendbirdAction.isCurrentUser(this.message.sender) + ? [styles['message-nickname'], styles['is-user']] + : styles['message-nickname'], + content: `${protectFromXSS(this.message.sender.nickname)} : ` + }); + messageContent.appendChild(nickname); + + const msg = createDivEl({ + className: [styles['message-content'], styles['is-file']], + content: protectFromXSS(this.message.name) + }); + msg.addEventListener('click', () => { + window.open(this.message.url); + }); + messageContent.appendChild(msg); + + const time = createDivEl({ className: styles.time, content: timestampToTime(this.message.createdAt) }); + time.addEventListener('mouseover', () => { + this._hoverOnTime(time, true); + }); + time.addEventListener('mouseleave', () => { + this._hoverOnTime(time, false); + }); + time.addEventListener('click', () => { + const messageDeleteModal = new MessageDeleteModal({ + channel: this.channel, + message: this.message + }); + messageDeleteModal.render(); + }); + messageContent.appendChild(time); + + if (this.channel.isGroupChannel()) { + const count = sendbirdAction.getReadReceipt(this.channel, this.message); + const read = createDivEl({ + className: count ? [styles.read, styles.active] : styles.read, + content: count + }); + messageContent.appendChild(read); + } + + root.appendChild(messageContent); + + if (isImage(this.message.type) && this.message.messageId) { + const imageContent = createDivEl({ className: styles['image-content'] }); + imageContent.addEventListener('click', () => { + window.open(this.message.url); + }); + const imageRender = document.createElement('img'); + imageRender.className = styles['image-render']; + imageRender.src = protectFromXSS(this.message.url); + imageRender.onload = () => { + Chat.getInstance().main.repositionScroll(imageRender.offsetHeight); + }; + imageContent.appendChild(imageRender); + root.appendChild(imageContent); + } + + return root; + } + + _createAdminElement() { + const root = createDivEl({ className: styles['chat-message'], id: this.message.messageId }); + const msg = createDivEl({ className: styles['message-admin'], content: protectFromXSS(this.message.message) }); + root.appendChild(msg); + return root; + } + + static getRootElementClasasName() { + return styles['chat-message']; + } + + static getReadReceiptElementClassName() { + return styles.active; + } +} + +export { Message }; diff --git a/javascript/javascript-basic/src/js/components/MessageDeleteModal.js b/javascript/javascript-basic/src/js/components/MessageDeleteModal.js new file mode 100644 index 00000000..cd473cc0 --- /dev/null +++ b/javascript/javascript-basic/src/js/components/MessageDeleteModal.js @@ -0,0 +1,45 @@ +import styles from '../../scss/message-delete-modal.scss'; +import { createDivEl, errorAlert, protectFromXSS } from '../utils'; +import { SendBirdAction } from '../SendBirdAction'; +import { Spinner } from './Spinner'; +import { Modal } from './Modal'; +import { Chat } from '../Chat'; + +const title = 'Delete Message'; +const description = 'Are you Sure? Do you want to delete message?'; +const submitText = 'DELETE'; + +class MessageDeleteModal extends Modal { + constructor({ channel, message }) { + super({ title, description, submitText }); + this.channel = channel; + this.message = message; + this._createElement(); + this._createHandler(); + } + + _createElement() { + const content = createDivEl({ + className: styles['modal-message'], + content: this.message.isFileMessage() ? protectFromXSS(this.message.name) : protectFromXSS(this.message.message) + }); + this.contentElement.appendChild(content); + } + + _createHandler() { + this.submitHandler = () => { + SendBirdAction.getInstance() + .deleteMessage({ channel: this.channel, message: this.message }) + .then(() => { + Spinner.remove(); + this.close(); + Chat.getInstance().main.removeMessage(this.message.messageId); + }) + .catch(error => { + errorAlert(error.message); + }); + }; + } +} + +export { MessageDeleteModal }; diff --git a/javascript/javascript-basic/src/js/components/Modal.js b/javascript/javascript-basic/src/js/components/Modal.js new file mode 100644 index 00000000..7bf5887a --- /dev/null +++ b/javascript/javascript-basic/src/js/components/Modal.js @@ -0,0 +1,63 @@ +import styles from '../../scss/modal.scss'; +import { createDivEl } from '../utils'; +import { Spinner } from './Spinner'; +import { body } from '../const'; + +class Modal { + constructor({ title, description, submitText }) { + this.contentElement = null; + this.cancelHandler = null; + this.submitHandler = null; + this.element = this._create({ title, description, submitText }); + } + + _create({ title, description, submitText }) { + const root = createDivEl({ className: styles['modal-root'] }); + const modal = createDivEl({ className: styles['modal-body'] }); + root.appendChild(modal); + + const titleText = createDivEl({ className: styles['modal-title'], content: title }); + modal.appendChild(titleText); + + const desc = createDivEl({ className: styles['modal-desc'], content: description }); + modal.appendChild(desc); + + this.contentElement = createDivEl({ className: styles['modal-content'] }); + modal.appendChild(this.contentElement); + + const bottom = createDivEl({ className: styles['modal-bottom'] }); + modal.appendChild(bottom); + const cancel = createDivEl({ className: styles['modal-cancel'], content: 'CANCEL' }); + cancel.addEventListener('click', () => { + if (this.cancelHandler) { + this.cancelHandler(); + } + this.close(); + }); + bottom.appendChild(cancel); + const submit = createDivEl({ className: styles['modal-submit'], content: submitText }); + submit.addEventListener('click', () => { + Spinner.start(modal); + if (this.submitHandler) { + this.submitHandler(); + } + }); + bottom.appendChild(submit); + + return root; + } + + close() { + if (body.contains(this.element)) { + body.removeChild(this.element); + } + } + + render() { + if (!body.querySelector(`.${styles['modal-root']}`)) { + body.appendChild(this.element); + } + } +} + +export { Modal }; diff --git a/javascript/javascript-basic/src/js/components/OpenChannelCreateModal.js b/javascript/javascript-basic/src/js/components/OpenChannelCreateModal.js new file mode 100644 index 00000000..8cd94a25 --- /dev/null +++ b/javascript/javascript-basic/src/js/components/OpenChannelCreateModal.js @@ -0,0 +1,50 @@ +import styles from '../../scss/open-create-modal.scss'; +import { errorAlert } from '../utils'; +import { SendBirdAction } from '../SendBirdAction'; +import { Spinner } from './Spinner'; +import { Modal } from './Modal'; + +class OpenChannelCreateModal extends Modal { + constructor({ title, description, submitText }) { + super({ title, description, submitText }); + this._createElement(); + this._createHandler(); + } + + _createElement() { + this.input = document.createElement('input'); + this.input.type = 'text'; + this.input.placeholder = 'Please enter name of Open Channel.'; + this.input.className = styles['modal-input']; + this.input.maxLength = 20; + this.contentElement.appendChild(this.input); + } + + _createHandler() { + this.cancelHandler = () => { + this.input.value = ''; + }; + + this.submitHandler = () => { + SendBirdAction.getInstance() + .createOpenChannel(this.input.value) + .then(channel => { + SendBirdAction.getInstance() + .enter(channel.url) + .then(() => { + this.input.value = ''; + Spinner.remove(); + this.close(); + }) + .catch(error => { + errorAlert(error.message); + }); + }) + .catch(error => { + errorAlert(error.message); + }); + }; + } +} + +export { OpenChannelCreateModal }; diff --git a/javascript/javascript-basic/src/js/components/OpenChannelItem.js b/javascript/javascript-basic/src/js/components/OpenChannelItem.js new file mode 100644 index 00000000..de6834da --- /dev/null +++ b/javascript/javascript-basic/src/js/components/OpenChannelItem.js @@ -0,0 +1,35 @@ +import styles from '../../scss/open-channel-item.scss'; +import { createDivEl, timestampToDateString } from '../utils'; + +class OpenChannelItem { + constructor({ channel, handler }) { + this.channel = channel; + this.element = this._createElement(handler); + } + + get title() { + return `# ${this.channel.name}`; + } + + get channelUrl() { + return this.channel.url; + } + + get createTimeString() { + return `Created on ${timestampToDateString(this.channel.createdAt)}`; + } + + _createElement(handler) { + const item = createDivEl({ className: styles['channel-item'], id: this.channelUrl }); + const title = createDivEl({ className: styles['item-title'], content: this.title }); + item.appendChild(title); + const desc = createDivEl({ className: styles['item-desc'], content: this.createTimeString }); + item.appendChild(desc); + item.addEventListener('click', () => { + if (handler) handler(); + }); + return item; + } +} + +export { OpenChannelItem }; diff --git a/javascript/javascript-basic/src/js/components/OpenChannelList.js b/javascript/javascript-basic/src/js/components/OpenChannelList.js new file mode 100644 index 00000000..d6d3187d --- /dev/null +++ b/javascript/javascript-basic/src/js/components/OpenChannelList.js @@ -0,0 +1,78 @@ +import { errorAlert } from '../utils'; +import { Spinner } from './Spinner'; +import { SendBirdAction } from '../SendBirdAction'; +import { OpenChannelItem } from './OpenChannelItem'; +import { List } from './List'; +import { body as targetEl } from '../const'; +import { ChatLeftMenu } from '../ChatLeftMenu'; + +let instance = null; + +class OpenChannelList extends List { + constructor() { + super('Open Channel List', true); + if (instance) { + return instance; + } + + this.scrollEventHandler = this._getOpenChannelList; + this.searchKeyword = ''; + instance = this; + } + + _getOpenChannelList(isInit = false, urlKeyword = '') { + Spinner.start(this.element); + + if (urlKeyword !== this.searchKeyword) { + this.searchKeyword = urlKeyword; + isInit = true; + } + + const listContent = this.getContentElement(); + if (isInit) { + listContent.innerHTML = ''; + } + + SendBirdAction.getInstance() + .getOpenChannelList(isInit, urlKeyword) + .then(openChannelList => { + openChannelList.forEach(channel => { + const handler = () => { + const existItem = ChatLeftMenu.getInstance().getChannelItem(channel.url); + if (existItem) { + existItem.click(); + this.close(); + } else { + SendBirdAction.getInstance() + .enter(item.channelUrl) + .then(() => { + this.close(); + }) + .catch(error => { + errorAlert(error.message); + }); + } + }; + const item = new OpenChannelItem({ channel, handler }); + listContent.appendChild(item.element); + }); + Spinner.remove(); + }) + .catch(error => { + errorAlert(error.message); + }); + } + + render() { + if (!targetEl.querySelector(`.${this.getRootClassName()}`)) { + targetEl.appendChild(this.element); + this._getOpenChannelList(true); + } + } + + static getInstance() { + return new OpenChannelList(); + } +} + +export { OpenChannelList }; diff --git a/javascript/javascript-basic/src/js/components/OpenChannelSearchBox.js b/javascript/javascript-basic/src/js/components/OpenChannelSearchBox.js new file mode 100644 index 00000000..4cb01d81 --- /dev/null +++ b/javascript/javascript-basic/src/js/components/OpenChannelSearchBox.js @@ -0,0 +1,36 @@ +import styles from '../../scss/list.scss'; +import { createDivEl } from '../utils'; +import { KEY_ENTER, OPEN_CHANNEL_SEARCH_URL } from '../const'; +import { OpenChannelList } from './OpenChannelList'; + +class OpenChannelSearchBox { + constructor() { + this.element = this._create(); + } + + _create() { + const searchChannelBox = createDivEl({ className: styles['list-search'] }); + const searchInputBox = document.createElement('input'); + searchInputBox.type = 'text'; + searchInputBox.id = OPEN_CHANNEL_SEARCH_URL; + searchInputBox.className = styles['search-input']; + searchInputBox.placeholder = 'Search by ChannelUrl...'; + searchInputBox.addEventListener('keydown', e => { + if (e.keyCode === KEY_ENTER) { + OpenChannelList.getInstance().scrollEventHandler(true, searchInputBox.value); + } + }); + + searchChannelBox.appendChild(searchInputBox); + return searchChannelBox; + } + + static clearText() { + const textBox = document.querySelector(`#${OPEN_CHANNEL_SEARCH_URL}`); + if (textBox) { + textBox.value = ''; + } + } +} + +export { OpenChannelSearchBox }; diff --git a/javascript/javascript-basic/src/js/components/Spinner.js b/javascript/javascript-basic/src/js/components/Spinner.js new file mode 100644 index 00000000..b7d83297 --- /dev/null +++ b/javascript/javascript-basic/src/js/components/Spinner.js @@ -0,0 +1,42 @@ +import styles from '../../scss/spinner.scss'; +import { createDivEl } from '../utils'; + +let instance = null; + +class Spinner { + constructor() { + if (instance) { + return instance; + } + this.element = this._createSpinner(); + instance = this; + } + + _createSpinner() { + const item = createDivEl({ className: styles['sb-spinner'] }); + const bubble = createDivEl({ className: styles['sb-spinner-bubble'] }); + item.appendChild(bubble); + return item; + } + + static start(target) { + const spinnerEl = Spinner.getInstance().element; + if (!target.contains(spinnerEl)) { + target.appendChild(spinnerEl); + } + } + + static remove() { + const spinnerEl = Spinner.getInstance().element; + const targetEl = spinnerEl.parentElement; + if (targetEl && targetEl.contains(spinnerEl)) { + spinnerEl.parentElement.removeChild(spinnerEl); + } + } + + static getInstance() { + return new Spinner(); + } +} + +export { Spinner }; diff --git a/javascript/javascript-basic/src/js/components/UserBlockModal.js b/javascript/javascript-basic/src/js/components/UserBlockModal.js new file mode 100644 index 00000000..71ee70f4 --- /dev/null +++ b/javascript/javascript-basic/src/js/components/UserBlockModal.js @@ -0,0 +1,55 @@ +import styles from '../../scss/user-block-modal.scss'; +import { createDivEl, errorAlert, protectFromXSS } from '../utils'; +import { SendBirdAction } from '../SendBirdAction'; +import { Spinner } from './Spinner'; +import { Modal } from './Modal'; +import { Chat } from '../Chat'; + +const blockTitle = 'Block User'; +const blockDescription = 'Are you Sure? Do you want to block this user?'; +const blockSubmitText = 'BLOCK'; + +const unblockTitle = 'Unblock User'; +const unblockDescription = 'Are you Sure? Do you want to unblock this user?'; +const unblockSubmitText = 'UNBLOCK'; + +class UserBlockModal extends Modal { + constructor({ user, isBlock = true }) { + isBlock + ? super({ title: blockTitle, description: blockDescription, submitText: blockSubmitText }) + : super({ title: unblockTitle, description: unblockDescription, submitText: unblockSubmitText }); + this.isBlock = isBlock; + this.user = user; + this._createElement(); + this._createHandler(); + } + + _createElement() { + const content = createDivEl({ className: styles['modal-user'] }); + + const image = createDivEl({ className: styles['user-profile'], background: protectFromXSS(this.user.profileUrl) }); + content.appendChild(image); + + const nickname = createDivEl({ className: styles['user-nickname'], content: protectFromXSS(this.user.nickname) }); + content.appendChild(nickname); + + this.contentElement.appendChild(content); + } + + _createHandler() { + this.submitHandler = () => { + SendBirdAction.getInstance() + .blockUser(this.user, this.isBlock) + .then(() => { + Chat.getInstance().main.updateBlockedList(this.user, this.isBlock); + Spinner.remove(); + this.close(); + }) + .catch(error => { + errorAlert(error.message); + }); + }; + } +} + +export { UserBlockModal }; diff --git a/javascript/javascript-basic/src/js/components/UserItem.js b/javascript/javascript-basic/src/js/components/UserItem.js new file mode 100644 index 00000000..799ec0cb --- /dev/null +++ b/javascript/javascript-basic/src/js/components/UserItem.js @@ -0,0 +1,63 @@ +import styles from '../../scss/user-item.scss'; +import { createDivEl, protectFromXSS, timestampFromNow, toggleClass } from '../utils'; + +class UserItem { + constructor({ user, handler }) { + this.user = user; + this.element = this._createElement(handler); + } + + get userId() { + return this.user.userId; + } + + get nickname() { + return protectFromXSS(this.user.nickname); + } + + get profileUrl() { + return protectFromXSS(this.user.profileUrl); + } + + get lastSeenTimeString() { + return this.user.lastSeenAt ? timestampFromNow(this.user.lastSeenAt) : ''; + } + + get isOnline() { + return this.user.connectionStatus === 'online'; + } + + _createElement(handler) { + const item = createDivEl({ className: styles['user-item'], id: this.userId }); + + const userInfo = createDivEl({ className: styles['user-info'] }); + item.appendChild(userInfo); + const profile = createDivEl({ className: styles['user-profile'], background: this.profileUrl }); + userInfo.appendChild(profile); + const nickname = createDivEl({ className: styles['user-nickname'], content: this.nickname }); + userInfo.appendChild(nickname); + const isOnline = createDivEl({ + className: this.isOnline ? [styles['user-online'], styles.active] : styles['user-online'] + }); + userInfo.appendChild(isOnline); + + const userState = createDivEl({ className: styles['user-state'] }); + item.appendChild(userState); + const lastSeenTime = createDivEl({ className: styles['user-time'], content: this.lastSeenTimeString }); + userState.appendChild(lastSeenTime); + const selectIcon = createDivEl({ className: styles['user-select'] }); + userState.appendChild(selectIcon); + item.addEventListener('click', () => { + toggleClass(item.querySelector(`.${UserItem.selectIconClassName}`), styles.active); + if (handler) handler(); + }); + + return item; + } + + static get selectIconClassName() { + return styles['user-select']; + } +} + +export { UserItem }; diff --git a/javascript/javascript-basic/src/js/components/UserList.js b/javascript/javascript-basic/src/js/components/UserList.js new file mode 100644 index 00000000..775d8c0d --- /dev/null +++ b/javascript/javascript-basic/src/js/components/UserList.js @@ -0,0 +1,133 @@ +import styles from '../../scss/user-list.scss'; +import { createDivEl, errorAlert, appendToFirst } from '../utils'; +import { List } from './List'; +import { Spinner } from './Spinner'; +import { SendBirdAction } from '../SendBirdAction'; +import { UserItem } from './UserItem'; +import { body as targetEl } from '../const'; +import { Chat } from '../Chat'; +import { ChatLeftMenu } from '../ChatLeftMenu'; +import { LeftListItem } from './LeftListItem'; + +let instance = null; + +class UserList extends List { + constructor() { + super('User List'); + if (instance) { + return instance; + } + + this.scrollEventHandler = this._getUserList; + this.closeEventHandler = this._close; + this.createBtn = this._addCreateBtn(); + this.selectedUserIds = []; + instance = this; + } + + _addCreateBtn() { + const createBtn = createDivEl({ className: styles['button-create'], content: 'CREATE' }); + const oldCreateBtn = this.buttonRootElement.getElementsByClassName(styles['button-create'])[0]; + if (oldCreateBtn) { + this.buttonRootElement.removeChild(oldCreateBtn); + } + appendToFirst(this.buttonRootElement, createBtn); + return createBtn; + } + + _createChannel() { + SendBirdAction.getInstance() + .createGroupChannel(this.selectedUserIds) + .then(channel => { + Chat.getInstance().render(channel.url, false); + const handler = () => { + Chat.getInstance().render(channel.url, false); + ChatLeftMenu.getInstance().activeChannelItem(channel.url); + }; + const item = new LeftListItem({ channel, handler }); + ChatLeftMenu.getInstance().addGroupChannelItem(item.element, true); + ChatLeftMenu.getInstance().activeChannelItem(channel.url); + Spinner.remove(); + this.close(); + }) + .catch(error => { + errorAlert(error.message); + }); + } + + _inviteChannel() { + const channelUrl = Chat.getInstance().channel.url; + SendBirdAction.getInstance() + .inviteGroupChannel(channelUrl, this.selectedUserIds) + .then(() => { + Spinner.remove(); + this.close(); + }) + .catch(error => { + errorAlert(error.message); + }); + } + + _updateCreateType(isInvite) { + this.createBtn = this._addCreateBtn(); + this.createBtn.innerHTML = isInvite ? 'INVITE' : 'CREATE'; + this.createBtn.addEventListener('click', () => { + Spinner.start(this.element); + if (isInvite) { + this._inviteChannel(); + } else { + this._createChannel(); + } + }); + } + + _getUserList(isInit = false) { + Spinner.start(this.element); + const sendbirdAction = SendBirdAction.getInstance(); + const listContent = this.getContentElement(); + sendbirdAction + .getUserList(isInit) + .then(userList => { + userList.forEach(user => { + if (!sendbirdAction.isCurrentUser(user)) { + const handler = () => { + this._toggleUserId(item.userId); + }; + const item = new UserItem({ user, handler }); + listContent.appendChild(item.element); + } + }); + Spinner.remove(); + }) + .catch(error => { + errorAlert(error.message); + }); + } + + _toggleUserId(userId) { + const index = this.selectedUserIds.indexOf(userId); + if (index > -1) { + this.selectedUserIds.splice(index, 1); + } else { + this.selectedUserIds.push(userId); + } + } + + _close() { + this.selectedUserIds = []; + } + + render(isInvite = false) { + if (!targetEl.querySelector(`.${this.getRootClassName()}`)) { + this._updateCreateType(isInvite); + targetEl.appendChild(this.element); + this._getUserList(true); + } + } + + static getInstance() { + return new UserList(); + } +} + +export { UserList }; diff --git a/javascript/javascript-basic/src/js/const.js b/javascript/javascript-basic/src/js/const.js new file mode 100644 index 00000000..6954d419 --- /dev/null +++ b/javascript/javascript-basic/src/js/const.js @@ -0,0 +1,14 @@ +export const APP_ID = '9DA1B1F4-0BE6-4DA8-82C5-2E81DAB56F23'; +export const USER_ID = 'user_id'; +export const DISPLAY_NONE = 'none'; +export const DISPLAY_BLOCK = 'block'; +export const DISPLAY_FLEX = 'flex'; +export const ACTIVE_CLASSNAME = 'active'; +export const KEY_ENTER = 13; +export const FILE_ID = 'attach_file_id'; +export const UPDATE_INTERVAL_TIME = 5 * 1000; +export const COLOR_RED = '#DC5960'; +export const MESSAGE_REQ_ID = 'reqId'; +export const OPEN_CHANNEL_SEARCH_URL = 'search_open_channel'; + +export const body = document.querySelector('body'); diff --git a/javascript/javascript-basic/src/js/index.js b/javascript/javascript-basic/src/js/index.js new file mode 100644 index 00000000..5cbeefcf --- /dev/null +++ b/javascript/javascript-basic/src/js/index.js @@ -0,0 +1,36 @@ +import { isEmpty, setCookie, getCookie } from './utils'; +import { USER_ID, KEY_ENTER } from './const'; + +const userIdEl = document.querySelector('#user_id'); +const nicknameEl = document.querySelector('#user_nickname'); +const buttonEl = document.querySelector('#login-button'); + +document.addEventListener('DOMContentLoaded', () => { + const cookieUserId = getCookie(USER_ID); + if (cookieUserId) { + userIdEl.value = cookieUserId; + } +}); + +nicknameEl.addEventListener('keydown', e => { + if (e.which === KEY_ENTER) { + login(); + } +}); + +buttonEl.addEventListener('click', () => { + login(); +}); + +const login = () => { + const userId = userIdEl.value.trim(); + const nickname = nicknameEl.value.trim(); + if (isEmpty(nickname)) { + alert('Please enter user nickname'); + return; + } + userIdEl.value = ''; + nicknameEl.value = ''; + setCookie(USER_ID, userId); + window.location.href = `chat.html?userid=${encodeURIComponent(userId)}&nickname=${encodeURIComponent(nickname)}`; +}; diff --git a/javascript/javascript-basic/src/js/main.js b/javascript/javascript-basic/src/js/main.js new file mode 100644 index 00000000..679d42a8 --- /dev/null +++ b/javascript/javascript-basic/src/js/main.js @@ -0,0 +1,104 @@ +import { getVariableFromUrl, isEmpty, redirectToIndex } from './utils'; +import { SendBirdAction } from './SendBirdAction'; +import { ChatLeftMenu } from './ChatLeftMenu'; +import { Chat } from './Chat'; +import { Spinner } from './components/Spinner'; +import { body, UPDATE_INTERVAL_TIME } from './const'; +import { SendBirdConnection } from './SendBirdConnection'; +import { SendBirdEvent } from './SendBirdEvent'; +import { LeftListItem } from './components/LeftListItem'; + +const sb = new SendBirdAction(); + +const chatLeft = new ChatLeftMenu(); +const chat = new Chat(); + +Spinner.start(body); + +const createConnectionHandler = () => { + const connectionManager = new SendBirdConnection(); + connectionManager.onReconnectStarted = () => { + Spinner.start(body); + console.log('[SendBird JS SDK] Reconnect : Started'); + connectionManager.channel = chat.channel; + }; + connectionManager.onReconnectSucceeded = () => { + console.log('[SendBird JS SDK] Reconnect : Succeeded'); + chatLeft.clear(); + chatLeft.updateUserInfo(SendBirdAction.getInstance().getCurrentUser()); + chatLeft.getGroupChannelList(true); + Spinner.start(body); + chat.refresh(connectionManager.channel); + }; + connectionManager.onReconnectFailed = () => { + console.log('[SendBird JS SDK] Reconnect : Failed'); + connectionManager.remove(); + redirectToIndex('SendBird Reconnect Failed...'); + }; +}; + +const createChannelEvent = () => { + const channelEvent = new SendBirdEvent(); + channelEvent.onChannelChanged = channel => { + if(channel._autoMarkAsRead) { + channel.markAsRead(); + } + chatLeft.updateItem(channel, true); + }; + channelEvent.onUserEntered = (openChannel, user) => { + if (SendBirdAction.getInstance().isCurrentUser(user)) { + const handler = () => { + chat.render(openChannel.url); + ChatLeftMenu.getInstance().activeChannelItem(openChannel.url); + }; + const item = new LeftListItem({ channel: openChannel, handler }); + chatLeft.addOpenChannelItem(item.element); + chat.render(openChannel.url); + } + }; + channelEvent.onUserJoined = (groupChannel, user) => { + const handler = () => { + chat.render(groupChannel.url, false); + ChatLeftMenu.getInstance().activeChannelItem(groupChannel.url); + }; + const item = new LeftListItem({ channel: groupChannel, handler }); + chatLeft.addGroupChannelItem(item.element); + chat.updateChatInfo(groupChannel); + }; + channelEvent.onUserLeft = (groupChannel, user) => { + if (SendBirdAction.getInstance().isCurrentUser(user)) { + chatLeft.removeGroupChannelItem(groupChannel.url); + } else { + chatLeft.updateItem(groupChannel); + } + chat.updateChatInfo(groupChannel); + }; + channelEvent.onChannelHidden = groupChannel => { + chatLeft.removeGroupChannelItem(groupChannel.url); + }; +}; + +const updateGroupChannelTime = () => { + setInterval(() => { + LeftListItem.updateLastMessageTime(); + }, UPDATE_INTERVAL_TIME); +}; + +document.addEventListener('DOMContentLoaded', () => { + const { userid, nickname } = getVariableFromUrl(); + if (isEmpty(userid) || isEmpty(nickname)) { + redirectToIndex('UserID and Nickname must be required.'); + } + sb + .connect(userid, nickname) + .then(user => { + chatLeft.updateUserInfo(user); + createConnectionHandler(); + createChannelEvent(); + updateGroupChannelTime(); + chatLeft.getGroupChannelList(true); + }) + .catch(() => { + redirectToIndex('SendBird connection failed.'); + }); +}); diff --git a/javascript/javascript-basic/src/js/utils.js b/javascript/javascript-basic/src/js/utils.js new file mode 100644 index 00000000..3ce548de --- /dev/null +++ b/javascript/javascript-basic/src/js/utils.js @@ -0,0 +1,179 @@ +import moment from 'moment'; + +export const timestampToTime = timestamp => { + const now = new Date().getTime(); + const nowDate = moment.unix(now.toString().length === 13 ? now / 1000 : now).format('MM/DD'); + + let date = moment.unix(timestamp.toString().length === 13 ? timestamp / 1000 : timestamp).format('MM/DD'); + if (date === 'Invalid date') { + date = ''; + } + + return nowDate === date + ? moment.unix(timestamp.toString().length === 13 ? timestamp / 1000 : timestamp).format('HH:mm') + : date; +}; + +export const timestampToDateString = timestamp => { + return moment.unix(timestamp.toString().length === 13 ? timestamp / 1000 : timestamp).format('LL'); +}; + +export const timestampFromNow = timestamp => { + return moment(timestamp).fromNow(); +}; + +export const isUrl = urlString => { + const regex = /^(http|https):\/\/[^ "]+$/; + return regex.test(urlString); +}; + +export const isImage = fileType => { + const regex = /^image\/.+$/; + return regex.test(fileType); +}; + +export const isEmpty = value => { + return value === null || value === undefined || value.length === 0; +}; + +export const isNull = value => { + try { + return value === null; + } catch (e) { + return false; + } +}; + +export const setCookie = (key, value) => { + document.cookie = `${key}=${value}; expires=Fri, 31 Dec 9999 23:59:59 GMT`; +}; + +export const getCookie = key => { + let name = `${key}=`; + let ca = document.cookie.split(';'); + for (let i = 0; i < ca.length; i++) { + let c = ca[i]; + if (!c) continue; + while (c.charAt(0) === ' ') { + c = c.substring(1); + } + if (c.indexOf(name) === 0) { + return c.substring(name.length, c.length); + } + } + return ''; +}; + +export const getVariableFromUrl = () => { + let vars = {}; + let hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); + for (let i = 0; i < hashes.length; i++) { + let hash = hashes[i].split('='); + vars[hash[0]] = hash[1]; + } + return vars; +}; + +export const errorAlert = (message, reload = true) => { + alert(message); + if (reload) { + location.reload(true); + } +}; + +export const redirectToIndex = message => { + if (message) { + errorAlert(message, false); + } + window.location.href = 'index.html'; +}; + +export const setDataInElement = (target, key, data) => { + target.dataset[`${key}`] = data; +}; + +export const getDataInElement = (target, key) => { + return target.dataset[`${key}`]; +}; + +export const createDivEl = ({ id, className, content, background }) => { + const el = document.createElement('div'); + if (id) { + el.id = id; + } + if (className) { + el.className = Array.isArray(className) ? className.join(' ') : className; + } + if (content) { + el.innerHTML = content; + } + if (background) { + el.style.backgroundImage = `url(${background})`; + } + return el; +}; + +export const isScrollBottom = target => { + return target.scrollTop + target.offsetHeight >= target.scrollHeight; +}; + +export const appendToFirst = (target, newElement) => { + if (target.childNodes.length > 0) { + target.insertBefore(newElement, target.childNodes[0]); + } else { + target.appendChild(newElement); + } +}; + +const hasClass = (target, className) => { + return target.classList + ? target.classList.contains(className) + : new RegExp('(^| )' + className + '( |$)', 'gi').test(target.className); +}; + +export const addClass = (target, className) => { + if (target.classList) { + if (!(className in target.classList)) { + target.classList.add(className); + } + } else { + if (target.className.indexOf(className) < 0) { + target.className += ` ${className}`; + } + } +}; + +export const removeClass = (target, className) => { + if (target.classList) { + target.classList.remove(className); + } else { + target.className = target.className.replace( + new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), + '' + ); + } +}; + +export const toggleClass = (target, className) => { + hasClass(target, className) ? removeClass(target, className) : addClass(target, className); +}; + +export const uuid4 = () => { + let d = new Date().getTime(); + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + const r = ((d + Math.random() * 16) % 16) | 0; + d = Math.floor(d / 16); + return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16); + }); +}; + +export const protectFromXSS = text => { + return typeof text === 'string' + ? text + .replace(/\&/g, '&') + .replace(/\/g, '>') + .replace(/\"/g, '"') + .replace(/\'/g, ''') + : text; +}; diff --git a/javascript/javascript-basic/src/scss/_animation.scss b/javascript/javascript-basic/src/scss/_animation.scss new file mode 100644 index 00000000..11f013c9 --- /dev/null +++ b/javascript/javascript-basic/src/scss/_animation.scss @@ -0,0 +1,32 @@ +// Mixin +@mixin keyframes($name) { + @-webkit-keyframes #{$name} { @content; } + @-moz-keyframes #{$name} { @content; } + @-o-keyframes #{$name} { @content; } + @-ms-keyframes #{$name} { @content; } + @keyframes #{$name} { @content; } +} + +@mixin transform-scale($size) { + -webkit-transform: scale($size); + -moz-transform: scale($size); + -ms-transform: scale($size); + -o-transform: scale($size); + transform: scale($size); +} + +@mixin animation($animation...) { + -webkit-animation: $animation; + -moz-animation: $animation; + -o-animation: $animation; + -ms-animation: $animation; + animation: $animation; +} + +@mixin animation-delay($delay) { + -webkit-animation-delay: $delay; + -moz-animation-delay: $delay; + -o-animation-delay: $delay; + -ms-animation-delay: $delay; + animation-delay: $delay; +} diff --git a/javascript/javascript-basic/src/scss/_common.scss b/javascript/javascript-basic/src/scss/_common.scss new file mode 100644 index 00000000..9727b042 --- /dev/null +++ b/javascript/javascript-basic/src/scss/_common.scss @@ -0,0 +1,10 @@ +@import 'normalize'; +@import 'variables'; +@import 'mixins'; +@import 'icons'; + +body { + display: flex; + font-family: $font-family-exo2; + -webkit-font-smoothing: antialiased; +} diff --git a/javascript/javascript-basic/src/scss/_icons.scss b/javascript/javascript-basic/src/scss/_icons.scss new file mode 100644 index 00000000..01c41b28 --- /dev/null +++ b/javascript/javascript-basic/src/scss/_icons.scss @@ -0,0 +1,40 @@ +// Icons +$ic-prefix: 'https://dxstmhyqfqr1o.cloudfront.net/web-basic/'; +$ic-input-user: 'icon-username-landing.svg'; +$ic-profile-default: 'image-profile.svg'; +$ic-add-normal: 'icon-add-normal.png'; +$ic-add-over: 'icon-add-over.png'; +$ic-close: 'icon-close.png'; +$ic-enter: 'icon-enter.png'; +$ic-check-unselect: 'icon-check-unselect.png'; +$ic-check-select: 'icon-check-select.png'; +$ic-empty-chat: 'img-empty.svg'; + +$ic-group: 'icon-group.png'; +$ic-hide-normal: 'icon-hide-normal.png'; +$ic-hide: 'icon-hide.png'; +$ic-group-add-normal: 'icon-group-add-normal.png'; +$ic-group-add: 'icon-group-add.png'; +$ic-leave-normal: 'icon-leave-normal.png'; +$ic-leave: 'icon-leave.png'; +$ic-attach-file-normal: 'icon-attach-file-normal.png'; +$ic-attach-file: 'icon-attach-file.png'; +$ic-arrow-normal: 'icon-arrow-nomal.png'; +$ic-arrow: 'icon-arrow.png'; +$ic-back: 'icon-back.png'; + +$ic-search: 'icon-search-nomal.png'; +$ic-search-over: 'icon-search-over.png'; + +@mixin icon($url, $size: cover, $position: center) { + background-image: url($ic-prefix + $url); + background-position: $position; + background-size: $size; + background-repeat: no-repeat; +} + +@mixin imageMessage() { + background-position: center; + background-size: 160px 160px; + background-repeat: no-repeat; +} \ No newline at end of file diff --git a/javascript/javascript-basic/src/scss/_mixins.scss b/javascript/javascript-basic/src/scss/_mixins.scss new file mode 100644 index 00000000..a954ed4b --- /dev/null +++ b/javascript/javascript-basic/src/scss/_mixins.scss @@ -0,0 +1,4 @@ +@import 'mixins/border-radius'; +@import 'mixins/state'; +@import 'mixins/transform'; +@import 'mixins/reset'; diff --git a/javascript/javascript-basic/src/scss/_normalize.scss b/javascript/javascript-basic/src/scss/_normalize.scss new file mode 100644 index 00000000..08e68694 --- /dev/null +++ b/javascript/javascript-basic/src/scss/_normalize.scss @@ -0,0 +1,450 @@ +/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */ + +/* Document + ========================================================================== */ + +/** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in + * IE on Windows Phone and in iOS. + */ + +html { + line-height: 1.15; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/* Sections + ========================================================================== */ + +/** + * Remove the margin in all browsers (opinionated). + */ + +body { + margin: 0; +} + +/** + * Add the correct display in IE 9-. + */ + +article, +aside, +footer, +header, +nav, +section { + display: block; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/* Grouping content + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + * 1. Add the correct display in IE. + */ + +figcaption, +figure, +main { + /* 1 */ + display: block; +} + +/** + * Add the correct margin in IE 8. + */ + +figure { + margin: 1em 40px; +} + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +pre { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/* Text-level semantics + ========================================================================== */ + +/** + * 1. Remove the gray background on active links in IE 10. + * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. + */ + +a { + background-color: transparent; /* 1 */ + -webkit-text-decoration-skip: objects; /* 2 */ +} + +/** + * 1. Remove the bottom border in Chrome 57- and Firefox 39-. + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} + +/** + * Prevent the duplicate application of `bolder` by the next rule in Safari 6. + */ + +b, +strong { + font-weight: inherit; +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct font style in Android 4.3-. + */ + +dfn { + font-style: italic; +} + +/** + * Add the correct background and color in IE 9-. + */ + +mark { + background-color: #ff0; + color: #000; +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + */ + +audio, +video { + display: inline-block; +} + +/** + * Add the correct display in iOS 4-7. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Remove the border on images inside links in IE 10-. + */ + +img { + border-style: none; +} + +/** + * Hide the overflow in IE. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change the font styles in all browsers (opinionated). + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font-family: sans-serif; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { + /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { + /* 1 */ + text-transform: none; +} + +/** + * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` + * controls in Android 4. + * 2. Correct the inability to style clickable types in iOS and Safari. + */ + +button, +html [type='button'], /* 1 */ +[type='reset'], +[type='submit'] { + -webkit-appearance: button; /* 2 */ +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type='button']::-moz-focus-inner, +[type='reset']::-moz-focus-inner, +[type='submit']::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +[type='button']:-moz-focusring, +[type='reset']:-moz-focusring, +[type='submit']:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Correct the padding in Firefox. + */ + +fieldset { + padding: 0.35em 0.75em 0.625em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * 1. Add the correct display in IE 9-. + * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Remove the default vertical scrollbar in IE. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10-. + * 2. Remove the padding in IE 10-. + */ + +[type='checkbox'], +[type='radio'] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type='number']::-webkit-inner-spin-button, +[type='number']::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type='search'] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. + */ + +[type='search']::-webkit-search-cancel-button, +[type='search']::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* Interactive + ========================================================================== */ + +/* + * Add the correct display in IE 9-. + * 1. Add the correct display in Edge, IE, and Firefox. + */ + +details, /* 1 */ +menu { + display: block; +} + +/* + * Add the correct display in all browsers. + */ + +summary { + display: list-item; +} + +/* Scripting + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + */ + +canvas { + display: inline-block; +} + +/** + * Add the correct display in IE. + */ + +template { + display: none; +} + +/* Hidden + ========================================================================== */ + +/** + * Add the correct display in IE 10-. + */ + +[hidden] { + display: none; +} diff --git a/javascript/javascript-basic/src/scss/_variables.scss b/javascript/javascript-basic/src/scss/_variables.scss new file mode 100644 index 00000000..53f99485 --- /dev/null +++ b/javascript/javascript-basic/src/scss/_variables.scss @@ -0,0 +1,39 @@ +// Color +$color-transparent: transparent !default; + +$color-black-border: #2C2D30 !default; +$color-black: #000000 !default; +$color-black-text: #555555 !default; +$color-black-text-light: #abb8c4 !default; + +$color-gray-admin: #e8ecef !default; +$color-gray-dark: #dedede !default; +$color-gray: #e3e3e3 !default; +$color-gray-light: #F8F8F8 !default; + +$color-white: #ffffff !default; + +$color-blue-dark: #328fe6 !default; +$color-blue: #32c5e6 !default; + + +$color-purple-darker: #463c66 !default; +$color-purple-dark: #4E4273 !default; +$color-purple: #6e5baa !default; +$color-purple-light: #6742d6 !default; + +$color-purple-deep: #673AB7 !default; + +$color-purple-text-dark: #7F6DA0 !default; +$color-purple-text: #c7b0ff !default; +$color-purple-text-light: #A08DCE !default; + +$color-green-online: #00C853 !default; + +$color-red: #DC5960 !default; + +$color-chat-border: #e0e2e5 !default; +$color-chat-select: #f8f9fa !default; + +// Font +$font-family-exo2: 'Exo 2'; diff --git a/javascript/javascript-basic/src/scss/chat-body.scss b/javascript/javascript-basic/src/scss/chat-body.scss new file mode 100644 index 00000000..71347597 --- /dev/null +++ b/javascript/javascript-basic/src/scss/chat-body.scss @@ -0,0 +1,13 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.chat-body { + display: flex; + flex-direction: column; + height: 100%; + max-height: calc(100vh - 180px); + overflow-y: auto; + overflow-x: hidden; + padding: 10px 0; +} diff --git a/javascript/javascript-basic/src/scss/chat-input.scss b/javascript/javascript-basic/src/scss/chat-input.scss new file mode 100644 index 00000000..089761eb --- /dev/null +++ b/javascript/javascript-basic/src/scss/chat-input.scss @@ -0,0 +1,74 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.chat-input { + display: flex; + padding: 20px; + border-top: 1px solid $color-chat-border; + background-color: $color-white; + + & > .typing-field { + display: none; + position: absolute; + bottom: 79px; + left: 220px; + width: calc(100vw - 220px - 240px); + padding: 6px 20px; + box-sizing: border-box; + background-color: rgba(0, 0, 0, 0.1); + color: $color-black-text; + opacity: 0.4; + vertical-align: middle; + font-size: 13px; + font-style: italic; + } + + & > .input-file { + display: flex; + width: 36px; + height: 36px; + border: 1px solid $color-chat-border; + border-right: 0; + background-color: $color-white; + cursor: pointer; + @include border-left-radius(4px); + @include icon($ic-attach-file-normal, 20px 20px, center center); + @include hover-focus { + border: 1px solid $color-black-border; + @include icon($ic-attach-file, 20px 20px, center center); + } + } + + & > .input-text { + display: flex; + font-size: 15px; + width: 100%; + height: 38px; + padding: 7px 8px 6px 8px; + box-sizing: border-box; + border: 1px solid $color-chat-border; + background-color: $color-white; + @include border-right-radius(4px); + @include hover-focus-active { + border: 1px solid $color-black-border; + } + + & > .input-text-area { + width: 100%; + outline: none; + border: 0; + resize: none; + line-height: 1.4; + background-color: $color-white; + overflow: hidden; + @include hover-focus { + outline: none; + border: 0; + resize: none; + padding-top: 2px; + line-height: 1.4; + } + } + } +} diff --git a/javascript/javascript-basic/src/scss/chat-main.scss b/javascript/javascript-basic/src/scss/chat-main.scss new file mode 100644 index 00000000..34279652 --- /dev/null +++ b/javascript/javascript-basic/src/scss/chat-main.scss @@ -0,0 +1,18 @@ +@import 'mixins'; +@import 'variables'; + +.chat-main-root { + display: flex; + flex-direction: row; + height: 100%; + overflow-y: auto; + overflow-x: hidden; + padding: 0; + + & > .chat-main { + display: flex; + flex-direction: column; + justify-content: space-between; + width: 100%; + } +} diff --git a/javascript/javascript-basic/src/scss/chat-menu.scss b/javascript/javascript-basic/src/scss/chat-menu.scss new file mode 100644 index 00000000..b54403ae --- /dev/null +++ b/javascript/javascript-basic/src/scss/chat-menu.scss @@ -0,0 +1,97 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.chat-menu-root { + display: flex; + flex-direction: column; + width: 240px; + min-width: 240px; + max-width: 240px; + background-color: $color-white; + box-sizing: border-box; + border-left: 1px solid $color-chat-border; + color: $color-black-border; + padding: 0; + + & > .menu-item { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + align-content: center; + padding: 10px 20px; + border-bottom: 1px solid $color-chat-border; + cursor: pointer; + + & > .menu-users, + & > .menu-blocked { + display: flex; + opacity: 0.6; + } + + & > .menu-arrow { + display: flex; + width: 36px; + height: 36px; + @include icon($ic-arrow-normal, 26px 26px, center center); + } + + @include hover-focus { + background-color: $color-chat-select; + + & > .menu-users, + & > .menu-blocked { + opacity: 1; + } + + & > .menu-arrow { + @include icon($ic-arrow, 26px 26px, center center); + } + } + } + + & > .menu-list { + display: none; + flex-direction: column; + position: absolute; + width: 239px; + height: calc(100% - 77px); + background: $color-white; + z-index: 999; + + & > .list-title { + display: flex; + align-items: center; + align-content: center; + padding: 10px 20px; + box-sizing: border-box; + color: $color-black-border; + border-bottom: 1px solid $color-chat-border; + cursor: pointer; + @include hover-focus { + background-color: $color-chat-select; + } + + & > .list-back { + display: flex; + width: 36px; + height: 36px; + @include icon($ic-back, 24px 24px, 0 center); + } + + & > .list-text { + display: flex; + } + } + + & > .list-body { + display: block; + flex-direction: column; + height: 100%; + max-height: calc(100% - 56px); + overflow-y: auto; + overflow-x: hidden; + } + } +} diff --git a/javascript/javascript-basic/src/scss/chat-top-menu.scss b/javascript/javascript-basic/src/scss/chat-top-menu.scss new file mode 100644 index 00000000..239bb56c --- /dev/null +++ b/javascript/javascript-basic/src/scss/chat-top-menu.scss @@ -0,0 +1,81 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.chat-top { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + height: 80px; + box-sizing: border-box; + padding: 15px 20px; + border: 1px solid transparent; + border-bottom: 1px solid $color-chat-border; + color: $color-black-border; + + & > .chat-title { + max-width: 800px; + font-size: 20px; + white-space: nowrap; + overflow: hidden; + -ms-text-overflow: ellipsis; + text-overflow: ellipsis; + } + & > .chat-title.is-group { + padding-left: 34px; + @include icon($ic-group, 27px 27px, 0 center); + } + + & > .chat-button { + display: flex; + flex-direction: row; + justify-content: flex-end; + width: 150px; + margin-left: 20px; + + & > .button-invite { + width: 36px; + height: 36px; + border: 1px solid $color-chat-border; + margin-right: 10px; + cursor: pointer; + @include border-radius(4px); + @include icon($ic-group-add-normal, 20px 20px, center center); + @include hover-focus { + cursor: pointer; + border: 1px solid $color-black-border; + @include icon($ic-group-add, 20px 20px, center center); + } + } + + & > .button-hide { + width: 36px; + height: 36px; + border: 1px solid $color-chat-border; + margin-right: 10px; + cursor: pointer; + @include border-radius(4px); + @include icon($ic-hide-normal, 20px 20px, center center); + @include hover-focus { + cursor: pointer; + border: 1px solid $color-black-border; + @include icon($ic-hide, 20px 20px, center center); + } + } + + & > .button-leave { + width: 36px; + height: 36px; + border: 1px solid $color-chat-border; + cursor: pointer; + @include border-radius(4px); + @include icon($ic-leave-normal, 20px 20px, center center); + @include hover-focus { + cursor: pointer; + border: 1px solid $color-black-border; + @include icon($ic-leave, 20px 20px, center center); + } + } + } +} diff --git a/javascript/javascript-basic/src/scss/chat-user-item.scss b/javascript/javascript-basic/src/scss/chat-user-item.scss new file mode 100644 index 00000000..649deefb --- /dev/null +++ b/javascript/javascript-basic/src/scss/chat-user-item.scss @@ -0,0 +1,34 @@ +@import 'mixins'; +@import 'variables'; + +.chat-user-item { + display: flex; + flex-direction: row; + align-items: center; + padding: 10px 20px; + cursor: pointer; + + & > .user-image { + display: flex; + width: 36px; + height: 36px; + margin-right: 10px; + background-size: 36px 36px; + background-position: center center; + background-repeat: no-repeat; + @include border-radius(50%); + } + + & > .user-nickname { + width: 154px; + max-width: 154px; + white-space: nowrap; + overflow: hidden; + -ms-text-overflow: ellipsis; + text-overflow: ellipsis; + } + & > .user-nickname.is-user { + font-weight: 600; + color: $color-purple-deep; + } +} diff --git a/javascript/javascript-basic/src/scss/chat.scss b/javascript/javascript-basic/src/scss/chat.scss new file mode 100644 index 00000000..9c9242ae --- /dev/null +++ b/javascript/javascript-basic/src/scss/chat.scss @@ -0,0 +1,51 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.chat-empty { + display: flex; + width: 100%; + height: 100%; + + & > .empty-content { + display: flex; + flex-direction: column; + align-items: center; + margin: auto; + text-align: center; + color: $color-black-text-light; + @include transform-translate(0, -50%); + + & > .content-title { + display: flex; + font-size: 28px; + } + + & > .content-image { + display: flex; + width: 80px; + height: 80px; + padding: 8px; + @include icon($ic-empty-chat, 80px 80px, center center); + } + + & > .content-desc { + display: flex; + font-size: 14px; + white-space: pre; + } + } +} + +.logo-image { + background-color: $color-white; + border-radius: 50%; +} + +.chat-root { + display: flex; + flex-direction: column; + justify-content: flex-start; + width: 100%; + height: 100%; +} diff --git a/javascript/javascript-basic/src/scss/index.scss b/javascript/javascript-basic/src/scss/index.scss new file mode 100644 index 00000000..fcf7f2d3 --- /dev/null +++ b/javascript/javascript-basic/src/scss/index.scss @@ -0,0 +1,136 @@ +@import 'common'; + +body { + background-color: $color-purple; +} + +.logo-image { + background-color: $color-white; + border-radius: 50%; +} + +.container { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + min-width: 900px; + min-height: 650px; + font-family: $font-family-exo2; + + .logo-image { + background-color: $color-white; + border-radius: 50%; + } + + & > .top { + display: flex; + justify-content: center; + align-items: center; + margin-top: 80px; + color: $color-white; + & > .logo { + display: flex; + align-items: center; + & > .logo-image { + display: flex; + align-items: center; + } + } + & > .title { + display: flex; + align-items: center; + & > .title-company { + display: flex; + align-items: center; + font-size: 30px; + font-weight: 600; + margin: 0 10px; + } + & > .title-desc { + display: flex; + align-items: center; + font-size: 26px; + font-weight: 200; + } + } + } + + & > .login { + display: flex; + margin-top: 40px; + flex-direction: column; + justify-content: center; + align-items: center; + + & > .desc { + display: flex; + color: $color-purple-text; + flex-direction: column; + align-items: center; + text-align: center; + & > .download { + display: flex; + text-align: center; + margin: 20px 0; + & > .download-sample { + color: $color-purple-text; + cursor: pointer; + @include hover { + cursor: pointer; + } + } + } + } + & > .form { + display: flex; + flex-direction: column; + margin-top: 10px; + & > .form-input { + display: flex; + margin-top: 10px; + border: 2px solid $color-white; + padding: 0 10px 0 40px; + width: 300px; + height: 50px; + font-size: 16px; + color: $color-black-text; + @include border-radius(2px); + @include icon($ic-input-user, 20px 20px, 10px center); + @include hover-focus { + border: 2px solid $color-blue; + } + } + & > .button { + display: flex; + justify-content: center; + margin-top: 10px; + width: 100%; + height: 48px; + background-color: $color-blue; + color: $color-white; + font-size: 16px; + font-weight: 700; + border: 0; + @include border-radius(2px); + cursor: pointer; + @include hover { + cursor: pointer; + } + } + } + } + + & > .image { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + margin-top: 50px; + color: $color-white; + } +} + +#login-button { + align-items: center; +} diff --git a/javascript/javascript-basic/src/scss/list-item.scss b/javascript/javascript-basic/src/scss/list-item.scss new file mode 100644 index 00000000..a476e87f --- /dev/null +++ b/javascript/javascript-basic/src/scss/list-item.scss @@ -0,0 +1,84 @@ +@import 'mixins'; +@import 'variables'; + +.list-item { + display: flex; + flex-direction: column; + padding: 6px 20px; + cursor: pointer; + @include hover { + background-color: $color-purple-darker; + } + & > .item-top { + display: flex; + color: $color-purple-text-light; + & > .item-count { + width: 18px; + height: 18px; + box-sizing: border-box; + border: 1px solid $color-purple-text-light; + align-items: center; + align-content: center; + text-align: center; + margin-right: 8px; + font-size: 13px; + line-height: 17px; + } + & > .item-title { + width: 100%; + max-width: 150px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + } + } + & > .item-bottom { + display: flex; + color: $color-purple-text-dark; + justify-content: space-between; + flex-direction: column; + font-size: 14px; + margin-top: 4px; + padding-left: 26px; + & > .item-message { + display: flex; + flex-direction: row; + justify-content: space-between; + & > .item-message-text { + width: 130px; + max-width: 130px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + color: $color-purple-text-light; + opacity: 0.7; + } + & > .item-message-unread { + display: none; + width: 16px; + height: 16px; + background-color: $color-red; + text-align: center; + color: $color-white; + font-size: 10px; + font-weight: 600; + line-height: 16px; + @include border-radius(50%); + } + & > .item-message-unread.active { + display: block; + } + } + & > .item-time { + display: flex; + font-size: 11px; + } + } +} + +.list-item.active { + & > .item-top { + color: $color-purple-text; + font-weight: 600; + } +} diff --git a/javascript/javascript-basic/src/scss/list.scss b/javascript/javascript-basic/src/scss/list.scss new file mode 100644 index 00000000..7365ce94 --- /dev/null +++ b/javascript/javascript-basic/src/scss/list.scss @@ -0,0 +1,106 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.list-root { + min-width: 980px; + width: 100vw; + height: 100vh; + max-height: 100vh; + overflow: hidden; + position: absolute; + z-index: 9999; + background-color: $color-white; + font-family: $font-family-exo2; + & > .list-body { + max-width: 700px; + min-width: 500px; + width: 100%; + height: 100%; + margin: 70px auto 50px auto; + display: flex; + box-sizing: border-box; + flex-direction: column; + & > .list-top { + width: 100%; + height: 70px; + padding: 10px 20px; + box-sizing: border-box; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + & > .list-title { + display: flex; + font-size: 30px; + font-weight: 700; + margin-left: 20px; + } + & > .list-button { + display: flex; + flex-direction: row; + margin-right: 20px; + + & > .button-exit { + width: 36px; + height: 36px; + text-align: center; + justify-content: center; + display: flex; + line-height: 36px; + cursor: pointer; + border: 1px solid $color-black-border; + @include border-radius(4px); + @include icon($ic-close, 20px 20px, center center); + @include hover-focus { + cursor: pointer; + border: 1px solid $color-gray; + background-color: $color-gray; + } + } + } + } + & > .list-hr { + height: 0; + margin: 8px 20px; + border-top: 1px solid $color-gray; + } + + & > .list-search { + box-sizing: border-box; + padding: 10px 20px; + overflow: hidden; + & > .search-input { + font-size: 18px; + font-family: $font-family-exo2; + box-sizing: border-box; + width: calc(100% - 40px); + height: 42px; + margin: 0 20px; + padding-left: 44px; + outline: none; + border: 1px solid $color-gray; + @include border-radius(4px); + @include icon($ic-search, 26px 26px, 8px center); + @include hover-focus { + @include icon($ic-search-over, 26px 26px, 8px center); + border: 1px solid $color-purple-light; + font-weight: 300; + } + &::placeholder { + color: $color-gray; + font-size: 18px; + font-weight: 300; + } + } + } + + & > .list-content { + box-sizing: border-box; + padding: 10px 20px; + max-height: calc(100vh - 205px); + overflow-y: auto; + overflow-x: hidden; + } + } +} diff --git a/javascript/javascript-basic/src/scss/main.scss b/javascript/javascript-basic/src/scss/main.scss new file mode 100644 index 00000000..824553ff --- /dev/null +++ b/javascript/javascript-basic/src/scss/main.scss @@ -0,0 +1,134 @@ +@import 'common'; +.body { + display: flex; + flex-direction: row; + width: 100%; + min-width: 980px; + font-family: $font-family-exo2; + & > .body-left { + display: flex; + flex-direction: column; + justify-content: space-between; + width: 220px; + height: 100vh; + background-color: $color-purple-dark; + & > .body-left-top { + display: flex; + padding: 20px; + justify-content: center; + & > .top-logo { + display: flex; + align-items: center; + & > .logo-image { + display: flex; + align-items: center; + } + } + & > .top-text { + color: $color-white; + display: flex; + align-items: center; + font-size: 30px; + font-weight: 600; + margin-left: 5px; + } + } + & > .body-left-list { + display: flex; + flex-direction: column; + height: calc(100vh - 170px); + color: $color-purple-text-dark; + .icon-create-chat { + width: 20px; + height: 20px; + @include icon($ic-add-normal, 17px 17px, center center); + @include hover { + cursor: pointer; + background-color: $color-purple-text-light; + } + } + & > .chat-type { + display: flex; + flex-direction: row; + justify-content: space-between; + font-family: $font-family-exo2; + font-weight: 400; + font-size: 12px; + line-height: 20px; + padding: 8px 20px; + & > .chat-type-title { + @include hover { + cursor: pointer; + font-weight: 600; + color: $color-purple-text-light; + } + } + } + & > .chat-list { + flex-direction: column; + width: 100%; + max-height: 450px; + overflow-y: auto; + overflow-x: hidden; + box-sizing: border-box; + & > .default-item { + display: block; + padding: 10px; + margin: 0 20px; + color: $color-purple-text-light; + font-size: 16px; + border: 1px dashed $color-purple-text-light; + @include border-radius(4px); + } + } + & > .chat-list.chat-list-group { + max-height: calc(100% - 130px); + } + } + & > .body-left-bottom { + display: flex; + padding: 20px; + background-color: $color-purple-darker; + & > .bottom-profile { + display: flex; + height: 40px; + align-items: center; + & > .image-profile { + display: flex; + align-items: center; + @include border-radius(50%); + } + } + & > .bottom-nickname { + display: flex; + flex-direction: column; + justify-content: center; + padding-left: 10px; + & > .nickname-title { + display: flex; + color: $color-purple-text-dark; + font-size: 14px; + } + & > .nickname-content { + display: inline-block; + max-width: 150px; + height: 18px; + color: $color-purple-text-light; + font-size: 16px; + overflow: hidden; + text-overflow: ellipsis; + -ms-text-overflow: ellipsis; + white-space: nowrap; + } + } + } + } + & > .body-center { + display: flex; + flex-direction: column; + width: 100%; + min-width: 500px; + height: 100%; + background-color: $color-white; + } +} \ No newline at end of file diff --git a/javascript/javascript-basic/src/scss/message-delete-modal.scss b/javascript/javascript-basic/src/scss/message-delete-modal.scss new file mode 100644 index 00000000..57c4db82 --- /dev/null +++ b/javascript/javascript-basic/src/scss/message-delete-modal.scss @@ -0,0 +1,14 @@ +@import 'mixins'; +@import 'variables'; + +.modal-message { + display: flex; + align-items: center; + padding: 10px 10px; + width: 100%; + border: 1px solid $color-red; + background-color: $color-white; + font-size: 18px; + margin: 10px 0; + @include border-radius(4px); +} diff --git a/javascript/javascript-basic/src/scss/message.scss b/javascript/javascript-basic/src/scss/message.scss new file mode 100644 index 00000000..e0baa648 --- /dev/null +++ b/javascript/javascript-basic/src/scss/message.scss @@ -0,0 +1,91 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.chat-message { + display: block; + flex-direction: row; + justify-content: space-between; + align-items: center; + width: 100%; + box-sizing: border-box; + padding: 0 20px; + margin-bottom: 8px; + border: 1px solid transparent; + + & > .message-content { + display: inline; + & > .message-nickname { + align-items: center; + display: inline; + justify-content: flex-start; + flex-direction: column; + cursor: pointer; + } + & > .message-nickname.is-user { + font-weight: 600; + color: $color-purple-deep; + cursor: initial; + } + + & > .message-content { + display: inline; + white-space: pre-line; + } + & > .message-content.is-file { + cursor: pointer; + @include hover-focus { + color: $color-blue-dark; + } + } + + & > .time { + display: inline; + margin-left: 8px; + font-size: 12px; + opacity: 0.5; + } + & > .time.is-user { + cursor: pointer; + } + + & > .read { + display: none; + vertical-align: middle; + text-align: center; + width: 18px; + height: 18px; + line-height: 17px; + margin-left: 8px; + font-size: 12px; + color: $color-white; + font-weight: 500; + @include border-radius(50%); + background: $color-red; + } + & > .read.active { + display: inline-block; + } + } + + & > .image-content { + display: block; + border-left: 2px solid $color-black-text; + padding-left: 10px; + margin-top: 8px; + cursor: pointer; + & > .image-render { + display: inline; + max-width: 300px; + max-height: 300px; + } + } + + & > .message-admin { + display: flex; + align-items: center; + width: 100%; + font-style: italic; + color: $color-black-text; + } +} diff --git a/javascript/javascript-basic/src/scss/mixins/_border-radius.scss b/javascript/javascript-basic/src/scss/mixins/_border-radius.scss new file mode 100644 index 00000000..95bb40a1 --- /dev/null +++ b/javascript/javascript-basic/src/scss/mixins/_border-radius.scss @@ -0,0 +1,59 @@ +@mixin border-radius($radius) { + border-radius: $radius; + -webkit-border-radius: $radius; + -moz-border-radius: $radius; + -ms-border-radius: $radius; + -o-border-radius: $radius; +} + +@mixin border-top-radius($radius) { + border-top-right-radius: $radius; + border-top-left-radius: $radius; + -webkit-border-top-right-radius: $radius; + -webkit-border-top-left-radius: $radius; + -moz-border-top-right-radius: $radius; + -moz-border-top-left-radius: $radius; + -ms-border-top-right-radius: $radius; + -ms-border-top-left-radius: $radius; + -o-border-top-right-radius: $radius; + -o-border-top-left-radius: $radius; +} + +@mixin border-right-radius($radius) { + border-bottom-right-radius: $radius; + border-top-right-radius: $radius; + -webkit-border-bottom-right-radius: $radius; + -webkit-border-top-right-radius: $radius; + -moz-border-bottom-right-radius: $radius; + -moz-border-top-right-radius: $radius; + -ms-border-bottom-right-radius: $radius; + -ms-border-top-right-radius: $radius; + -o-border-bottom-right-radius: $radius; + -o-border-top-right-radius: $radius; +} + +@mixin border-bottom-radius($radius) { + border-bottom-right-radius: $radius; + border-bottom-left-radius: $radius; + -webkit-border-bottom-right-radius: $radius; + -webkit-border-bottom-left-radius: $radius; + -moz-border-bottom-right-radius: $radius; + -moz-border-bottom-left-radius: $radius; + -ms-border-bottom-right-radius: $radius; + -ms-border-bottom-left-radius: $radius; + -o-border-bottom-right-radius: $radius; + -o-border-bottom-left-radius: $radius; +} + +@mixin border-left-radius($radius) { + border-bottom-left-radius: $radius; + border-top-left-radius: $radius; + -webkit-border-bottom-left-radius: $radius; + -webkit-border-top-left-radius: $radius; + -moz-border-bottom-left-radius: $radius; + -moz-border-top-left-radius: $radius; + -ms-border-bottom-left-radius: $radius; + -ms-border-top-left-radius: $radius; + -o-border-bottom-left-radius: $radius; + -o-border-top-left-radius: $radius; +} diff --git a/javascript/javascript-basic/src/scss/mixins/_reset.scss b/javascript/javascript-basic/src/scss/mixins/_reset.scss new file mode 100644 index 00000000..eac43c4c --- /dev/null +++ b/javascript/javascript-basic/src/scss/mixins/_reset.scss @@ -0,0 +1,9 @@ +@mixin reset { + margin: 0; + padding: 0; + font-size: 100%; + line-height: 1; + width: auto; + height: auto; + box-sizing: initial; +} diff --git a/javascript/javascript-basic/src/scss/mixins/_state.scss b/javascript/javascript-basic/src/scss/mixins/_state.scss new file mode 100644 index 00000000..94e4cea3 --- /dev/null +++ b/javascript/javascript-basic/src/scss/mixins/_state.scss @@ -0,0 +1,58 @@ +@mixin hover { + &:hover { @content; } +} + +@mixin plain-hover { + &, + &:hover { @content; } +} + +@mixin focus { + &:focus { @content; } +} + +@mixin plain-focus { + &, + &:focus { @content; } +} + +@mixin hover-focus { + &:hover, + &:focus { @content; } +} + +@mixin plain-hover-focus { + &, + &:hover, + &:focus { @content; } +} + +@mixin hover-focus-active { + &:hover, + &:focus, + &:active { @content; } +} + +@mixin after { + &::after { + @content + } +} + +@mixin before { + &::before { + @content + } +} + +@mixin before-after { + &::after, &::before { + @content + } +} + +@mixin plain-before-after { + &, &::after, &::before { + @content + } +} diff --git a/javascript/javascript-basic/src/scss/mixins/_transform.scss b/javascript/javascript-basic/src/scss/mixins/_transform.scss new file mode 100644 index 00000000..026f6d1f --- /dev/null +++ b/javascript/javascript-basic/src/scss/mixins/_transform.scss @@ -0,0 +1,7 @@ +@mixin transform-translate($x, $y) { + -webkit-transform: translate($x, $y); + -moz-transform: translate($x, $y); + -ms-transform: translate($x, $y); + -o-transform: translate($x, $y); + transform: translate($x, $y); +} diff --git a/javascript/javascript-basic/src/scss/modal.scss b/javascript/javascript-basic/src/scss/modal.scss new file mode 100644 index 00000000..3590e65d --- /dev/null +++ b/javascript/javascript-basic/src/scss/modal.scss @@ -0,0 +1,74 @@ +@import 'mixins'; +@import 'variables'; + +.modal-root { + display: flex; + position: absolute; + width: 100vw; + height: 100vh; + z-index: 9999; + background-color: rgba(0, 0, 0, 0.5); + + & > .modal-body { + display: flex; + flex-direction: column; + box-sizing: border-box; + width: 450px; + background-color: $color-white; + margin: auto; + padding: 24px; + @include border-radius(4px); + @include transform-translate(0, -50%); + + & > .modal-title { + display: flex; + font-size: 26px; + font-weight: 600; + margin-bottom: 8px; + } + + & > .modal-desc { + display: flex; + color: $color-black-text; + font-size: 14px; + font-weight: 300; + } + + & > .modal-content { + display: flex; + margin: 10px 0; + } + + & > .modal-bottom { + display: flex; + justify-content: flex-end; + & > .modal-cancel { + display: flex; + margin-right: 12px; + color: $color-black-text-light; + border: 1px solid $color-black-text-light; + cursor: pointer; + padding: 6px; + @include border-radius(4px); + @include hover-focus { + color: $color-purple-light; + border: 1px solid $color-purple-light; + } + } + & > .modal-submit { + display: flex; + color: $color-white; + background-color: $color-blue; + border: 1px solid $color-blue; + cursor: pointer; + padding: 6px; + font-weight: 600; + @include border-radius(4px); + @include hover-focus { + background-color: $color-blue-dark; + border: 1px solid $color-blue-dark; + } + } + } + } +} \ No newline at end of file diff --git a/javascript/javascript-basic/src/scss/open-channel-item.scss b/javascript/javascript-basic/src/scss/open-channel-item.scss new file mode 100644 index 00000000..b6770cd2 --- /dev/null +++ b/javascript/javascript-basic/src/scss/open-channel-item.scss @@ -0,0 +1,32 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.channel-item { + display: flex; + flex-direction: column; + padding: 8px 50px 8px 20px; + border: 1px solid transparent; + border-bottom: 1px solid $color-gray-dark; + cursor: pointer; + @include hover-focus { + cursor: pointer; + border: 1px solid $color-purple-light; + @include icon($ic-enter, 24px 24px, calc(100% - 20px) center); + @include border-radius(2px); + } + + & > .item-title { + display: flex; + font-size: 20px; + font-weight: 500; + } + + & > .item-desc { + display: flex; + font-size: 14px; + font-weight: 300; + color: #353535; + margin-top: 6px; + } +} diff --git a/javascript/javascript-basic/src/scss/open-create-modal.scss b/javascript/javascript-basic/src/scss/open-create-modal.scss new file mode 100644 index 00000000..2f30f112 --- /dev/null +++ b/javascript/javascript-basic/src/scss/open-create-modal.scss @@ -0,0 +1,19 @@ +@import 'mixins'; +@import 'variables'; + +.modal-input { + display: flex; + width: 100%; + height: 35px; + border: 1px solid $color-gray-dark; + background-color: $color-gray-light; + font-size: 18px; + padding: 2px 10px; + margin: 10px 0; + @include border-radius(4px); + @include focus { + outline: none; + background-color: $color-white; + border: 1px solid $color-purple-light; + } +} diff --git a/javascript/javascript-basic/src/scss/spinner.scss b/javascript/javascript-basic/src/scss/spinner.scss new file mode 100644 index 00000000..7bf66632 --- /dev/null +++ b/javascript/javascript-basic/src/scss/spinner.scss @@ -0,0 +1,71 @@ +@import 'mixins'; +@import 'variables'; + +.sb-spinner { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + opacity: 0.6; + background-color: $color-white; + flex-direction: column; + justify-content: center; + display: flex; + + .sb-spinner-bubble { + color: $color-black; + font-size: 10px; + margin: 80px auto; + position: relative; + text-indent: -9999em; + -webkit-animation-delay: -0.16s; + animation-delay: -0.16s; + @include transform-translate(0, -2em); + @include plain-before-after { + @include border-radius(50%); + width: 1.5em; + height: 1.5em; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; + -webkit-animation: load7 1.8s infinite ease-in-out; + animation: load7 1.8s infinite ease-in-out; + } + @include before-after { + content: ''; + position: absolute; + top: 0; + } + @include before { + left: -3.5em; + -webkit-animation-delay: -0.32s; + animation-delay: -0.32s; + } + @include after { + left: 3.5em; + } + } + +} + +@-webkit-keyframes load7 { + 0%, + 80%, + 100% { + box-shadow: 0 2.5em 0 -1.3em; + } + 40% { + box-shadow: 0 2.5em 0 0; + } +} +@keyframes load7 { + 0%, + 80%, + 100% { + box-shadow: 0 2.5em 0 -1.3em; + } + 40% { + box-shadow: 0 2.5em 0 0; + } +} + diff --git a/javascript/javascript-basic/src/scss/user-block-modal.scss b/javascript/javascript-basic/src/scss/user-block-modal.scss new file mode 100644 index 00000000..9df0631c --- /dev/null +++ b/javascript/javascript-basic/src/scss/user-block-modal.scss @@ -0,0 +1,34 @@ +@import 'mixins'; +@import 'variables'; + +.modal-user { + display: flex; + align-items: center; + padding: 10px 10px; + width: 100%; + border: 1px solid $color-red; + background-color: $color-white; + font-size: 18px; + margin: 10px 0; + @include border-radius(4px); + + & > .user-profile { + display: flex; + width: 36px; + height: 36px; + margin-right: 10px; + background-size: 36px 36px; + background-position: center center; + background-repeat: no-repeat; + @include border-radius(50%); + } + + & > .user-nickname { + width: 330px; + max-width: 330px; + white-space: nowrap; + overflow: hidden; + -ms-text-overflow: ellipsis; + text-overflow: ellipsis; + } +} diff --git a/javascript/javascript-basic/src/scss/user-item.scss b/javascript/javascript-basic/src/scss/user-item.scss new file mode 100644 index 00000000..de417bfd --- /dev/null +++ b/javascript/javascript-basic/src/scss/user-item.scss @@ -0,0 +1,77 @@ +@import 'mixins'; +@import 'variables'; +@import 'icons'; + +.user-item { + display: flex; + padding: 8px 20px 8px 20px; + border: 1px solid transparent; + border-bottom: 1px solid $color-gray-dark; + justify-content: space-between; + cursor: pointer; + @include hover-focus { + cursor: pointer; + border: 1px solid $color-purple-light; + @include border-radius(2px); + } + + & > .user-info { + display: flex; + align-items: center; + + & > .user-profile { + display: flex; + width: 40px; + height: 40px; + @include icon($ic-profile-default, 40px 40px, center center); + } + + & > .user-nickname { + margin: 0 10px; + font-size: 18px; + max-width: 250px; + overflow: hidden; + text-overflow: ellipsis; + -ms-text-overflow: ellipsis; + white-space: nowrap; + } + + & > .user-online { + display: flex; + width: 8px; + height: 8px; + border: 1px solid $color-black-text-light; + background-color: $color-black-text-light; + opacity: 0.4; + @include border-radius(50%); + } + & > .user-online.active { + border: 1px solid $color-green-online; + background-color: $color-green-online; + opacity: 1; + } + } + + & > .user-state { + display: flex; + align-items: center; + + & > .user-time { + display: flex; + color: $color-black-text-light; + margin-right: 10px; + } + + & > .user-select { + display: flex; + width: 30px; + height: 30px; + opacity: 0.4; + @include icon($ic-check-unselect, 30px 30px, center center); + } + & > .user-select.active { + opacity: 1; + @include icon($ic-check-select, 30px 30px, center center); + } + } +} diff --git a/javascript/javascript-basic/src/scss/user-list.scss b/javascript/javascript-basic/src/scss/user-list.scss new file mode 100644 index 00000000..bc99f7b4 --- /dev/null +++ b/javascript/javascript-basic/src/scss/user-list.scss @@ -0,0 +1,23 @@ +@import 'mixins'; +@import 'variables'; + +.button-create { + width: 80px; + height: 36px; + text-align: center; + justify-content: center; + display: flex; + line-height: 36px; + font-weight: 600; + color: $color-white; + cursor: pointer; + background-color: $color-blue; + border: 1px solid $color-blue; + margin-right: 12px; + @include border-radius(4px); + @include hover-focus { + cursor: pointer; + background-color: $color-blue-dark; + border: 1px solid $color-blue-dark; + } +} diff --git a/javascript/javascript-basic/webpack.config.js b/javascript/javascript-basic/webpack.config.js new file mode 100644 index 00000000..ca1f8f99 --- /dev/null +++ b/javascript/javascript-basic/webpack.config.js @@ -0,0 +1,75 @@ +'use strict'; +const path = require('path'); +const webpack = require('webpack'); +const ExtractTextPlugin = require('extract-text-webpack-plugin'); + +const PRODUCTION = 'production'; + +module.exports = () => { + const config = { + entry: { + index: ['babel-polyfill', './src/js/index.js', './src/scss/index.scss'], + main: ['babel-polyfill', './src/js/main.js', './src/scss/main.scss'] + }, + output: { + path: path.resolve(__dirname, './dist'), + filename: 'sample.[name].js', + library: '[name]', + libraryExport: 'default', + libraryTarget: 'umd', + publicPath: 'dist' + }, + devtool: 'cheap-eval-source-map', + devServer: { + publicPath: '/dist/', + compress: true, + port: 9000 + }, + module: { + rules: [ + { + // SCSS + test: /\.scss$/, + use: ExtractTextPlugin.extract({ + fallback: 'style-loader', + use: [ + { + loader: 'css-loader', + options: { + module: true, + minimize: process.env.WEBPACK_MODE === PRODUCTION, + // sourceMap: true, + localIdentName: '[local]' + } + }, + { + loader: 'sass-loader' + } + ] + }) + }, + { + // ESLint + enforce: 'pre', + test: /\.js$/, + exclude: /node_modules/, + loader: 'eslint-loader', + options: { failOnError: true } + }, + { + // ES6 + test: /\.js$/, + loader: 'babel-loader', + exclude: '/node_modules/' + } + ] + }, + plugins: [ + new ExtractTextPlugin({ + filename: 'sample.[name].css' + }) + ] + }; + + return config; +}; diff --git a/javascript/javascript-live-chat/.babelrc b/javascript/javascript-live-chat/.babelrc new file mode 100644 index 00000000..a659ff45 --- /dev/null +++ b/javascript/javascript-live-chat/.babelrc @@ -0,0 +1,10 @@ +{ + "presets": [ + "@babel/preset-env" + ], + "env": { + "test": { + "presets": ["@babel/preset-env"] + } + } +} \ No newline at end of file diff --git a/javascript/javascript-live-chat/.eslintrc.js b/javascript/javascript-live-chat/.eslintrc.js new file mode 100644 index 00000000..503cd056 --- /dev/null +++ b/javascript/javascript-live-chat/.eslintrc.js @@ -0,0 +1,20 @@ +module.exports = { + 'env': { + 'browser': true, + 'commonjs': true, + 'es6': true + }, + 'extends': 'eslint:recommended', + 'parserOptions': { + 'sourceType': 'module' + }, + 'parser': 'babel-eslint', + 'rules': { + 'indent': ['error', 2], + 'semi': 1, + 'no-console': 1, + 'camelcase': 1, + 'no-unused-vars': 1, + 'no-useless-escape': 1 + } +}; diff --git a/javascript/javascript-live-chat/.prettierignore b/javascript/javascript-live-chat/.prettierignore new file mode 100644 index 00000000..52999c0b --- /dev/null +++ b/javascript/javascript-live-chat/.prettierignore @@ -0,0 +1,2 @@ +README.md +.eslintrc.js \ No newline at end of file diff --git a/javascript/javascript-live-chat/.prettierrc b/javascript/javascript-live-chat/.prettierrc new file mode 100644 index 00000000..f65aabcb --- /dev/null +++ b/javascript/javascript-live-chat/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "printWidth": 120 +} \ No newline at end of file diff --git a/javascript/javascript-live-chat/README.md b/javascript/javascript-live-chat/README.md new file mode 100644 index 00000000..8e6b6f71 --- /dev/null +++ b/javascript/javascript-live-chat/README.md @@ -0,0 +1,148 @@ +# Sendbird JavaScript Chat Sample +This is a sample chat built using the [Sendbird SDK](https://github.com/sendbird/SendBird-SDK-JavaScript). It can be used to add a functional chat to any website. + + +## [Demo](https://sample.sendbird.com/livechat/) + +You can try out a live demo from the link [here](https://sample.sendbird.com/livechat/). Choose any 'User ID' and 'Nickname' to log in and participate in chats. + + +## Setup +1. The `body` must have a `div` element whose id is `sb_chat`. we recommend width and height to 400px or over both. + +```html + +
+ +``` + +2. Import the [`SendBird SDK`](https://github.com/sendbird/SendBird-SDK-JavaScript). +3. Import the `liveChat.SendBird.js` file. +```javascript + + +``` + + +## Customizing the sample +If you refresh your browser window, you need to reconnect to SendBird. To retain connection on browser refresh, you must implement an appropriate `event handler`. + +If you wish to issue an `access_token` for your user, modify the `connect function` in `src/sendbird.js`. + +> Require that you have Node v8.x+ installed. + +> `node-sass` package requires XCode developer tools (MacOS only) and Node.js version matching. If you have any trouble in the installation, see https://www.npmjs.com/package/node-sass. + +1. Install npm +```bash +npm install +``` + +2. Modify files. +```bash +npm run start:dev +``` + +3. Start sample. +```bash +npm start +``` + + +## Advanced +### Connect other APP or Channel +If you want to connect other application or channel, you need to change variable `appId` or `channelUrl` in `index.html`. + +```html +... + + + + + + +``` + +### Start with User connect +If you want to start this sample with user connect, you can using `startWithConnect()`. + +```html +... + + + + + +``` + +### Enter Channel +If you want to enter channel, you can using `enterChannel()`. + +```javascript +... +var channelUrl = ''; +liveChat.enterChannel(channelUrl, function() { + // do something... +}); +... +``` + +### Exit Channel +If you want to exit current channel, you can using `exitChannel()`. + +```javascript +... +liveChat.exitChannel(function() { + // do something... +}); +... +``` + + +## File Structure +``` + |-- dist + |-- liveChat.SendBird.js - SendBird Chat Bundle file + |-- node_modules + |-- ... - (node packages) + |-- src + |-- js + |-- elements + |-- elements.js - elements root class + |-- spinner.js - spinner element + |-- chat-board.js - board element + |-- login-board.js - login element + |-- message-board.js - message element + |-- sendbird.js - sendbird functions + |-- chat.js - chat functions + |-- scss + |-- mixins + |-- _border-radius.scss - border radius mixin + |-- _box-shadow.scss - box shadow mixin + |-- _state.scss - element state mixin + |-- _transform.scss - transform mixin + |-- _reset.scss - clean css mixin + |-- _mixins.scss - import mixin + |-- _variables.scss - css variables + |-- _animation.scss - animation + |-- _icons.scss - icon + |-- chat.scss - main css +|-- .eslintrc.js - lint setting +|-- webpack.config.js - webpack setting +|-- package.json - npm package +|-- SendBird.min.js - SendBird SDK +|-- index.html - sample file +|-- README.md +``` diff --git a/javascript/javascript-live-chat/SendBird.min.js b/javascript/javascript-live-chat/SendBird.min.js new file mode 100644 index 00000000..ea7ddb20 --- /dev/null +++ b/javascript/javascript-live-chat/SendBird.min.js @@ -0,0 +1,6 @@ +/** + * Copyright (c) 2016 Sendbird DBA (Smile Family, Inc.) + * Sendbird JavaScript SDK v3.0.140 + */ + +!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n(require("axios"),require("form-data"),require("ws")):"function"==typeof define&&define.amd?define(["axios","form-data","ws"],n):(e=e||self).SendBird=n(e.axios,e.FormData,e.WebSocket)}(this,function(d,h,r){"use strict";function ie(e){return(ie="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function c(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}function i(e,n){for(var t=0;te.length)&&(n=e.length);for(var t=0,r=new Array(n);tthis.reconnectParams.retryCount){for(var c in this.disconnect({clearSession:!1,err:new oe("Websocket connection failed.",oe.WEBSOCKET_CONNECTION_FAILED)},null),this.reconnectCount=0,this.sb.connectionHandlers)this.sb.connectionHandlers[c].onReconnectFailed();return this.sb.connecting=!1,this.sb.reconnecting=!1,this.sb.isReconnectingOnError=!1,void this.sb.ConnectionManager.errorAllReadyHandler()}this.sb.onReconnectTimerCancel=function(){a.reconnectCount=0},this.sb.reconnectTimer=setTimeout(function(){a.sb.reconnectTimer=null,a.sb.onReconnectTimerCancel=null,a.client&&a.client.disconnect(!0);var e=new L.ConnectionHandler;a.client=new L(a.sb,e),a.sb.loginHandler=function(e,n){if(e)e.isSessionKeyExpiredError?o.refresh(function(){}):(clearTimeout(a.sb.reconnectTimer),a.sb.reconnectTimer=null,a.reconnect(i,!1));else{for(var t in a.reconnectCount=0,a.sb.connecting=!1,a.sb.reconnecting=!1,a.sb.isReconnectingOnError=!1,a.sb.connectionHandlers)a.sb.connectionHandlers[t].onReconnectSucceeded();if(a.sb.ConnectionManager.processAllReadyHandler(null),a.sb.isReconnectingOnError)for(var r in a.sb.ConnectionManager.networkHandlers)a.sb.ConnectionManager.networkHandlers[r].onReconnected();Object.keys(l.enteredChannels).forEach(function(t){l.enteredChannels[t].enter(function(e,n){e&&(e=a.cls.FileMessageQueue,delete l.enteredChannels[t],e.delete(t))})})}},e.onOpen=function(){le.debug("reconnect onOpen"),a.sb.loginTimer=setTimeout(function(){le.debug("reconnect loginTimer timeout"),a.sb.loginTimer=null,a.reconnect(i,!0)},a.sb.Options.websocketResponseTimeout),a.sb.onLoginTimerCancel=null,a.sb.reconnecting=!1},e.onMessage=function(e){s.onRawCommandReceived(e)},e.onError=function(e){le.debug("reconnect onError",e),a.sb.isReconnectingOnError=!0,a.sb.ConnectionManager.errorAllReadyHandler(),a.reconnect(i,!0)},e.onClose=function(){le.debug("reconnect onClose"),a.sb.reconnecting=!1},r.checkRouting(function(e,n){e?a.reconnect(i,!0):(a.sb.getCurrentApiHost()!==n.apiHost&&r.get("/",null,function(){}),a.client.connect(i,null,n.wsHost))})},this.reconnectDelay)}}},{key:"disconnect",value:function(e,n){var t=se.get(this.sb._iid),r=t.container.ackStateMap,i=this.cls,a=i.GroupChannel,s=i.OpenChannel,i=e.clearSession,e=e.err;if(this.sb.loginTimer&&(clearTimeout(this.sb.loginTimer),this.sb.onLoginTimerCancel&&(this.sb.onLoginTimerCancel(),this.sb.onLoginTimerCancel=null),this.sb.loginTimer=null),this.sb.reconnectTimer&&(clearTimeout(this.sb.reconnectTimer),this.sb.onReconnectTimerCancel&&(this.sb.onReconnectTimerCancel(),this.sb.onReconnectTimerCancel=null),this.sb.reconnectTimer=null),this.client&&(this.reconnectCount=0,this.client.disconnect(!0),this.client=null),i){for(var o in s.clearEnteredChannels(),s.clearCache(),a.clearCache(),this.sb.globalTimer&&(clearInterval(this.sb.globalTimer),this.sb.globalTimer=null),r)clearTimeout(r[o].timer);this.sb.currentUser=null,t.set("ackStateMap",{}),t.set("subscribedUnreadMessageCount",{all:0,custom_types:{},ts:0}),t.set("auth",new b)}e&&(this.flushConnectionCallbacks(e,null),this.sb.connecting=!1,this.sb.reconnecting=!1,this.sb.isReconnectingOnError=!1),n&&n(null,null)}},{key:"flushConnectionCallbacks",value:function(n,t){var e=this.sb.connectionCallbacks;this.sb.connectionCallbacks=[],e.forEach(function(e){return e(n,t)})}},{key:"isConnected",get:function(){return this.client&&this.client.getConnectionState()===this.sb.ConnectionState.OPEN}}]),n}(),G=function(){function u(e){var n=e.type,t=e.nullable,r=void 0!==t&&t,i=e.optional,a=void 0!==i&&i,s=e.optionalIf,t=void 0===s?null:s,i=e.ignoreIf,s=void 0===i?null:i,i=e.defaultValue,i=void 0===i?null:i,e=e.constraint,e=void 0===e?null:e;c(this,u),this.type=n,this.nullable=r,this.optional=a,this.optionalIf=t,this.ignoreIf=s,this.defaultValue=i,this.constraint=e}return o(u,[{key:"isMatchingType",value:function(t){function n(e,n){return"string"==typeof n?ie(e)===n||"array"===n&&Array.isArray(e)||"file"===n&&ue.isFile(e)||"null"===n&&null===e||"date"===n&&e instanceof Date:"function"==typeof n?e instanceof n:"object"===ie(n)&&-1C.ts){if(C.all!==U.unread_cnt.all&&(b=!0),C.all=0<=U.unread_cnt.all?U.unread_cnt.all:0,U.unread_cnt.custom_types)for(var S in U.unread_cnt.custom_types)C.custom_types[S]!==U.unread_cnt.custom_types[S]&&(b=!0),C.custom_types[S]=U.unread_cnt.custom_types[S];b=b&&0=H.createAt,t=g.sb.currentUser;t&&w&&(t.nickname!==H._sender.nickname&&(t.nickname=H._sender.nickname),t.plainProfileUrl!==H._sender.plainProfileUrl&&(t.plainProfileUrl=H._sender.plainProfileUrl),ue.deepEqual(t.metaData,H._sender.metaData)||(t.metaData=H._sender.metaData));var r,t=!1,i=!1;if(!w&&!n&&U&&U.hasOwnProperty("old_values")){var n=U.old_values.mention_type||H.mentionType,a=U.old_values.mentioned_user_ids||H.mentionedUsers.map(function(e){return e.userId});if(n===_.MentionType.USERS&&H.mentionType===_.MentionType.USERS){for(var s=!1,o=!1,l=0;l=Ae.get(this)&&(Ae.set(this,t),this.memberCount=e,this.joinedMemberCount=n)}},{key:"hide",value:function(i,a,e){var s=this,n=T(G.parse(arguments,[new G({type:"boolean",optional:!0,defaultValue:!1}),new G({type:"boolean",optional:!0,defaultValue:!0}),new G({type:"callback"})]),4),t=n[0];return i=n[1],a=n[2],e=n[3],$(this._iid,function(r){t?r(t,null):se.get(s._iid).container.apiClient.hideGroupChannel({channelUrl:s.url,hidePreviousMessages:i,allowAutoUnhide:a},function(e,n){var t;e||(t=B.get(s._iid).GroupChannel,s.isHidden=!0,s.hiddenState=a?t.HiddenState.HIDDEN_ALLOW_AUTO_UNHIDE:t.HiddenState.HIDDEN_PREVENT_AUTO_UNHIDE,i&&s._setGroupChannelUnreadCount(0,0),n.hasOwnProperty("ts_message_offset")&&(s._messageOffsetTimestamp=n.ts_message_offset),t.cachedChannels[s.url]=s),r(e,n)})},e)}},{key:"unhide",value:function(e){var i=this;return $(this._iid,function(r){se.get(i._iid).container.apiClient.unhideGroupChannel({channelUrl:i.url},function(e,n){var t;e||(t=B.get(i._iid).GroupChannel,i.isHidden=!1,i.hiddenState=t.HiddenState.UNHIDDEN,t.cachedChannels[i.url]=i),r(e,n)})},e)}},{key:"freeze",value:function(e){var i=this;return $(this._iid,function(r){se.get(i._iid).container.apiClient.freeze({channelUrl:i.url,isGroupChannel:!0,freezing:!0},function(e,n){var t;e||(t=B.get(i._iid).GroupChannel,i.isFrozen=!0,t.cachedChannels[i.url]=i),r(e,null)})},e)}},{key:"unfreeze",value:function(e){var i=this;return $(this._iid,function(r){se.get(i._iid).container.apiClient.freeze({channelUrl:i.url,isGroupChannel:!0,freezing:!1},function(e,n){var t;e||(t=B.get(i._iid).GroupChannel,i.isFrozen=!1,t.cachedChannels[i.url]=i),r(e,null)})},e)}},{key:"delete",value:function(e){var r=this;return $(this._iid,function(t){se.get(r._iid).container.apiClient.deleteGroupChannel({channelUrl:r.url},function(e,n){e||B.get(r._iid).GroupChannel.removeCachedChannel(r.url),t(e,n)})},e)}},{key:"markAsRead",value:function(){var i=this,e=B.get(this._iid).Command,a=jn.getInstance(this._iid),e=e.bRead({channelUrl:this.url});a.sendCommand(e,function(e,n){var t;if(a.getErrorFirstCallback()&&(n=(t=[e,n])[0],e=t[1]),!n&&a.currentUser&&(i.updateReadReceipt(a.currentUser.userId,e.getJsonElement().ts),0=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:n}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,a=!0,s=!1;return{s:function(){t=e[Symbol.iterator]()},n:function(){var e=t.next();return a=e.done,e},e:function(e){s=!0,i=e},f:function(){try{a||null==t.return||t.return()}finally{if(s)throw i}}}}(this.members);try{for(a.s();!(s=a.n()).done;){var s=s.value;n.currentUser.userId===s.userId||s.state!==t.JOINED||e.sender&&e.sender.userId===s.userId||this.cachedDeliveryReceiptStatus[s.userId]=e.createdAt&&i.push(s)}return i}return[]}},{key:"getUnreadMembers",value:function(e,n){var t=1=t&&(r.end=0,r.start=n,r=B.get(this._iid).Command.bTypeStart({channelUrl:this.url,time:r.start}),e.sendCommand(r,null))}},{key:"endTyping",value:function(){var e=jn.getInstance(this._iid),n=(new Date).getTime(),t=e.Options.typingIndicatorThrottle;("number"!=typeof t||t<1e3||9e3=t&&(r.start=0,r.end=n,r=B.get(this._iid).Command.bTypeEnd({channelUrl:this.url,time:r.end}),e.sendCommand(r,null))}},{key:"invalidateTypingStatus",value:function(){var e,n=Ue.get(this),t=(new Date).getTime(),r=!1;for(e in n)1e4<=t-n[e].ts&&(delete n[e],r=!0);return r}},{key:"getTypingMembers",value:function(){var e,n=[];for(e in Ue.get(this)){var t=this.memberMap[e];t&&n.push(t)}return n}},{key:"getTypingUsers",value:function(){var e,n=Ue.get(this),t=[];for(e in n){var r=n[e].user;t.push(r)}return t}},{key:"updateTypingStatus",value:function(e,n){var t=Ue.get(this);n?t[e.userId]={user:e,ts:(new Date).getTime()}:delete t[e.userId]}},{key:"isTyping",value:function(){var e=Ue.get(this);return 0!==Object.keys(e).length}},{key:"registerScheduledUserMessage",value:function(e,n){var i=this,t=B.get(this._iid),a=t.ScheduledUserMessage,t=t.ScheduledUserMessageParams,t=T(G.parse(arguments,[new G({type:t,constraint:function(e){return"string"==typeof e.message&&"string"==typeof e._getScheduleString()}}),new G({type:"callback"})]),3),s=t[0];return e=t[1],n=t[2],$(this._iid,function(r){s?r(s,null):se.get(i._iid).container.apiClient.registerScheduledUserMessage({groupChannelParams:e,channelUrl:i.url,isOpenChannel:!1},function(e,n){var t=null;e||(t=new a(n),(n=jn.getInstance(i._iid).currentUser)&&t._sender&&n.userId===t._sender.userId&&(n.nickname=t._sender.nickname,n.plainProfileUrl=t._sender.plainProfileUrl,n.metaData=t._sender.metaData)),r(e,t)})},n)}},{key:"getPushPreference",value:function(e){var i=this;return $(this._iid,function(r){se.get(i._iid).container.apiClient.getMyPushTriggerOption({channelUrl:i.url},function(e,n){var t=null;if(!e){try{t=n.enable}catch(e){t=!1}i.isPushEnabled=t}r&&r(e,t)})},e)}},{key:"setPushPreference",value:function(e,n){var i=this;return $(this._iid,function(t){var r=B.get(i._iid).GroupChannel;se.get(i._iid).container.apiClient.setMyPushTriggerOption({channelUrl:i.url,enable:e},function(e,n){e||(i.isPushEnabled=n.enable,i.isPushEnabled||(i.myPushTriggerOption=r.PushTriggerOption.OFF)),t(e,n)})},n)}},{key:"getMyPushTriggerOption",value:function(e){var i=this;return $(this._iid,function(r){se.get(i._iid).container.apiClient.getMyPushTriggerOption({channelUrl:i.url},function(e,n){var t=null;if(!e){try{t=n.push_trigger_option||a.PushTriggerOption.DEFAULT}catch(e){le.debug(e)}i.myPushTriggerOption=t}r(e,t)})},e)}},{key:"setMyPushTriggerOption",value:function(e,n){var i=this,t=B.get(this._iid).GroupChannel,t=T(G.parse(arguments,[new G({type:t.PushTriggerOption}),new G({type:"callback"})]),3),a=t[0];return e=t[1],n=t[2],$(this._iid,function(r){a?r(a,null):se.get(i._iid).container.apiClient.setMyPushTriggerOption({channelUrl:i.url,pushTriggerOption:e},function(e,n){var t=null;if(!e){try{t=n.push_trigger_option}catch(e){le.debug(e)}i.myPushTriggerOption=t}r(e,t)})},n)}},{key:"setMyCountPreference",value:function(e,n){var i=this,a=B.get(this._iid).GroupChannel,t=T(G.parse(arguments,[new G({type:a.CountPreference}),new G({type:"callback"})]),3),s=t[0];return e=t[1],n=t[2],$(this._iid,function(r){s?r(s,null):se.get(i._iid).container.apiClient.setMyCountPreference({channelUrl:i.url,countPreference:e},function(e,n){var t=null;e||(t=i.myCountPreference=n.count_preference,i._setGroupChannelUnreadCount(i.unreadMessageCount,i.unreadMentionCount),a.cachedChannels[i.url]=i),r(e,t)})},n)}},{key:"resetMyHistory",value:function(e){var i=this;return $(this._iid,function(r){se.get(i._iid).container.apiClient.resetMyHistory({channelUrl:i.url},function(e,n){var t;!e&&n.hasOwnProperty("ts_message_offset")&&(t=B.get(i._iid).GroupChannel,i._messageOffsetTimestamp=n.ts_message_offset,t.cachedChannels[i.url]=i),r(e,n)})},e)}},{key:"messageOffsetTimestamp",get:function(){return this._messageOffsetTimestamp}}],[{key:"buildFromSerializedData",value:function(e){var n=B.get(this._iid),t=n.User,r=n.Member,i=n.GroupChannel,a=n.BaseMessage,s=n.UserMessage,o=n.FileMessage,n=n.AdminMessage,e=X.deserialize(e);return new i({channel_url:e.url,name:e.name,cover_url:e.coverUrl,data:e.data,custom_type:e.customType,invited_at:e.invitedAt,created_at:e.createdAt/1e3,is_access_code_required:e.isAccessCodeRequired,is_distinct:e.isDistinct,is_super:e.isSuper,is_broadcast:e.isBroadcast,is_public:e.isPublic,is_discoverable:e.isDiscoverable,is_hidden:e.isHidden,is_ephemeral:e.isEphemeral,is_muted:e.myMutedState,is_push_enabled:e.isPushEnabled,freeze:e.isFrozen,unread_message_count:e.unreadMessageCount,unread_mention_count:e.unreadMentionCount,push_trigger_option:e.myPushTriggerOption,count_preference:e.myCountPreference,hidden_state:e.hiddenState,member_count:e.memberCount,joined_member_count:e.joinedMemberCount,member_state:e.myMemberState,my_role:e.myRole,user_last_read:e.myLastRead,ts_message_offset:e.messageOffsetTimestamp,message_survival_seconds:e.messageSurvivalSeconds,read_receipt:e.cachedReadReceiptStatus,delivery_receipt:e.cachedDeliveryReceiptStatus,members:e.members.map(function(e){return r.objectify(p({user:e},e))}),last_message:null!=(i=e.lastMessage)&&"object"===ie(i)?i.messageType===a.MESSAGE_TYPE_USER?new s(s.objectify(p(p({},i),{},{channel:{url:i.channelUrl,channelType:i.channelType},user:i.sender,mentionedUsers:i.mentionedUsers}))):i.messageType===a.MESSAGE_TYPE_FILE?new o(o.objectify(p(p({},i),{},{channel:{url:i.channelUrl,channelType:i.channelType},user:i.sender,mentionedUsers:i.mentionedUsers}))):new n(n.objectify(p(p({},i),{},{channel:{url:i.channelUrl,channelType:i.channelType},mentionedUsers:i.mentionedUsers}))):null,created_by:null!==e.creator&&void 0!==e.creator&&"object"===ie(e.creator)?t.objectify(e.creator):null,inviter:null!==e.inviter&&void 0!==e.inviter&&"object"===ie(e.inviter)?t.objectify(e.inviter):null})}},{key:"upsert",value:function(e){var n,t=B.get(this._iid).GroupChannel,r=new t(e);return t.cachedChannels.hasOwnProperty(r.url)?(r.isEphemeral&&(n=t.cachedChannels[r.url],e.last_message=n.lastMessage,e.unread_message_count=n.unreadMessageCount),t.cachedChannels[r.url].update(e)):t.cachedChannels[r.url]=r,t.cachedChannels[r.url]}},{key:"removeCachedChannel",value:function(e){var n=B.get(this._iid),t=n.GroupChannel,n=n.FileMessageQueue;t.cachedChannels[e]&&delete t.cachedChannels[e],n.delete(e)}},{key:"clearCache",value:function(){Ce[this._iid]={},B.get(this._iid).FileMessageQueue.clear()}},{key:"getChannel",value:function(n,e){var t,r=T(G.parse(arguments,[new G({type:"string",constraint:function(e){return 0 + + + + + + + + + + + + + + + + Live Chat Sample + + + + + + + +
+ + + + + version 0.7.0 +
+
+ +
+
+ +
+
+ + + + + 1080p +
+
+
+ + RockBird | Live at International Music Concert + + +
+
+ 3,365 watching now ∙Started streaming 1 hours ago +
+
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/javascript/javascript-live-chat/package.json b/javascript/javascript-live-chat/package.json new file mode 100644 index 00000000..0400d9b1 --- /dev/null +++ b/javascript/javascript-live-chat/package.json @@ -0,0 +1,31 @@ +{ + "name": "Sample-JS-Web-Live-Chat", + "version": "1.0.0", + "description": "Sendbird Live Chat", + "main": "index.js", + "scripts": { + "start:dev": "./node_modules/.bin/webpack-dev-server", + "build": "./node_modules/.bin/webpack --mode=production", + "start": "npm run build && node server.js" + }, + "author": "SendBird", + "license": "ISC", + "devDependencies": { + "@babel/core": "^7.12.10", + "@babel/preset-env": "^7.12.11", + "babel-eslint": "^10.1.0", + "babel-loader": "^8.2.2", + "babel-polyfill": "^6.26.0", + "css-loader": "^5.0.1", + "eslint": "^7.18.0", + "eslint-loader": "^2.1.1", + "node-sass": "^5.0.0", + "prettier": "^2.2.1", + "sass-loader": "^10.1.1", + "style-loader": "^2.0.0", + "webpack": "^5.15.0", + "webpack-cli": "^4.4.0", + "webpack-dev-server": "^3.11.2" + }, + "dependencies": {} +} diff --git a/javascript/javascript-live-chat/server.js b/javascript/javascript-live-chat/server.js new file mode 100644 index 00000000..18f0e743 --- /dev/null +++ b/javascript/javascript-live-chat/server.js @@ -0,0 +1,14 @@ +const express = require('express'); +const app = express(); + +const PORT = 9000; + +app.use(express.static('dist')); +app.use(express.static('./')); + +app.get('/', function (req, res) { + res.sendfile('index.html'); +}); + +app.listen(PORT); +console.log(`[SERVER RUNNING] 127.0.0.1:${PORT}`); diff --git a/javascript/javascript-live-chat/src/js/adapter.js b/javascript/javascript-live-chat/src/js/adapter.js new file mode 100644 index 00000000..74f79db0 --- /dev/null +++ b/javascript/javascript-live-chat/src/js/adapter.js @@ -0,0 +1,150 @@ +'use strict'; + +const GLOBAL_HANDLER = 'GLOBAL_HANDLER'; +const GET_MESSAGE_LIMIT = 30; + +export const KeyCode = { + ENTER: 13, + KR: 229, +}; + +class SendbirdAdapter { + constructor(appId) { + this.api = new window.SendBird({ appId: appId }); + this.messageListQuery = null; + this.channel = null; + } + + reset() { + this.channel = null; + this.api.removeChannelHandler(GLOBAL_HANDLER); + } + + /* + User + */ + isConnected() { + return !!this.api.currentUser; + } + isCurrentUser(user) { + return this.api.currentUser.userId === user.userId; + } + + connect(userId, nickname, action) { + this.api.connect(userId.trim(), (user, error) => { + if (error) { + console.error(error); + return; + } + this.api.updateCurrentUserInfo(nickname.trim(), '', (response, error) => { + if (error) { + console.error(error); + return; + } + action(); + }); + }); + } + + disconnect(action) { + if (this.isConnected()) { + this.api.disconnect(() => { + action(); + }); + } + } + + /* + Channel + */ + enterChannel(channelUrl, action) { + this.api.OpenChannel.getChannel(channelUrl, (channel, error) => { + if (error) { + console.error(error); + return; + } + channel.enter((response, error) => { + if (error) { + console.error(error); + return; + } + this.channel = channel; + action(); + }); + }); + } + + exitChannel(callback) { + this.channel.exit((response, error) => { + if (error) { + console.error(error); + return; + } + this.channel = null; + callback(); + }); + } + + /* + Message + */ + getMessageList(action, isInit) { + if (!this.messageListQuery || isInit) { + this.messageListQuery = this.channel.createPreviousMessageListQuery(); + } + if (this.messageListQuery.hasMore && !this.messageListQuery.isLoading) { + this.messageListQuery.load(GET_MESSAGE_LIMIT, !isInit, (messageList, error) => { + if (error) { + console.error(error); + return; + } + action(messageList); + }); + } + } + + sendMessage(textMessage, action) { + this.channel.sendUserMessage(textMessage, (message, error) => { + if (error) { + console.error(error); + return; + } + action(message); + }); + } + + /* + Handler + */ + createHandler(onMessageReceived) { + let channelHandler = new this.api.ChannelHandler(); + channelHandler.onMessageReceived = onMessageReceived; + channelHandler.onMessageDeleted = (channel, messageId) => { + var deletedMessage = document.getElementById(messageId); + if (deletedMessage) { + deletedMessage.remove(); + } + }; + this.api.addChannelHandler(GLOBAL_HANDLER, channelHandler); + } + + connectionHandler(channelUrl, liveChat) { + let ConnectionHandler = new this.api.ConnectionHandler(); + ConnectionHandler.onReconnectStarted = function (id) { + console.log('onReconnectStarted'); + liveChat.$spinner.attachTo(liveChat.$messageBoard.$content); + }; + + ConnectionHandler.onReconnectSucceeded = function (id) { + console.log('onReconnectSucceeded'); + liveChat.enterChannel(channelUrl); + }; + + ConnectionHandler.onReconnectFailed = function (id) { + console.log('onReconnectFailed'); + }; + this.api.addConnectionHandler('CONNECTION_HANDLER', ConnectionHandler); + } +} + +export { SendbirdAdapter as default }; diff --git a/javascript/javascript-live-chat/src/js/chat.js b/javascript/javascript-live-chat/src/js/chat.js new file mode 100644 index 00000000..64bebb07 --- /dev/null +++ b/javascript/javascript-live-chat/src/js/chat.js @@ -0,0 +1,177 @@ +'use strict'; + +import SendBirdAdapter from './adapter.js'; +import Element from './elements/element.js'; +import Spinner from './elements/spinner.js'; +import ChatBoard from './elements/chat-board.js'; +import LoginBoard from './elements/login-board.js'; +import MessageBoard from './elements/message-board.js'; + +const ELEMENT_ID = 'sb_chat'; +const ERROR_MESSAGE_SDK = 'Please import "SendBird SDK" on first.'; +const ERROR_MESSAGE_APP_ID = 'Please pass "APP_ID" when start.'; +const ERROR_MESSAGE_USER_INFO = 'Please pass "USER_ID" and "NICKNAME" when start.'; +const ERROR_MESSAGE_CHANNEL_URL = 'Please pass "CHANNEL_URL" when start.'; +const ERROR_MESSAGE = 'Please create "sb_chat" element on first.'; + +window.WebFontConfig = { + google: { families: ['Lato:400,700'] }, +}; + +class LiveChat { + constructor() {} + + init(appId, arg) { + if (!window.SendBird) { + console.error(ERROR_MESSAGE_SDK); + return; + } + if (!appId) { + console.error(ERROR_MESSAGE_APP_ID); + return; + } + switch (arg.type) { + case 'channel': + if (!arg.data.channelUrl) { + console.error(ERROR_MESSAGE_CHANNEL_URL); + return; + } + break; + case 'user': + if (!arg.data.userId || !arg.data.nickname) { + console.error(ERROR_MESSAGE_USER_INFO); + return; + } + break; + } + this.loadGoogleFont(); + + let _this = this; + this.$chat = new Element(document.getElementById(ELEMENT_ID)); + if (this.$chat) { + this.adapter = new SendBirdAdapter(appId); + this.$spinner = new Spinner(); + this.$chatBoard = new ChatBoard(this.$chat); + this.$messageBoard = new MessageBoard(); + + _this.$messageBoard.leave.on('click', (e) => { + _this.adapter.disconnect(() => { + _this.$chatBoard.replaceElement(_this.$messageBoard, _this.$loginBoard); + }); + }); + + this.$messageBoard.$content.on('scroll', (e) => { + if (_this.$messageBoard.$content.getScrollY() === 0) { + _this.adapter.getMessageList((messageList) => { + _this.$messageBoard.render(messageList, true); + }); + } + if (_this.$messageBoard.$content.isScrollBottom()) { + _this.$messageBoard.removeBottomBar(); + } + }); + + _this.$messageBoard.send.on('click', () => { + let textMessage = _this.$messageBoard.getMessage(); + _this.$messageBoard.clearInput(); + if (textMessage) { + textMessage = textMessage.replace(/<[/]?\s*br\s*[/]?>/gi, '\n'); + _this.adapter.sendMessage(textMessage, (message) => { + _this.$messageBoard.render([message], false, true); + _this.clearOverflowedMessages(); + }); + } + }); + } + } + + start(appId, channelUrl) { + this.init(appId, { + type: 'channel', + data: { + channelUrl: channelUrl, + }, + }); + + if (this.$chat) { + let _this = this; + this.$loginBoard = new LoginBoard(); + this.$loginBoard.onLogin(() => { + if (!_this.$loginBoard.$login.hasClass('disabled')) { + _this.$loginBoard.disable(); + _this.$spinner.attachTo(_this.$loginBoard.$login); + + _this.adapter.connect(_this.$loginBoard.$userId.val(), _this.$loginBoard.$nickname.val(), () => { + _this.$spinner.remove(_this.$loginBoard.$login); + _this.$loginBoard.reset(); + _this.$spinner.attachTo(_this.$messageBoard.$content); + + _this.$chatBoard.replaceElement(_this.$loginBoard, _this.$messageBoard); + _this.adapter.connectionHandler(channelUrl, _this); + _this.enterChannel(channelUrl); + }); + } + }); + this.$chatBoard.appendElement(this.$loginBoard); + } else { + console.error(ERROR_MESSAGE); + } + } + + startWithConnect(appId, userId, nickname, callback) { + let _this = this; + _this.init(appId, { + type: 'user', + data: { + userId: userId, + nickname: nickname, + }, + }); + if (_this.$chat) { + _this.adapter.connect(userId, nickname, () => { + _this.$spinner.attachTo(_this.$messageBoard.$content); + _this.$chatBoard.appendElement(_this.$messageBoard); + callback(); + }); + } else { + console.error(ERROR_MESSAGE); + } + } + + enterChannel(channelUrl, callback) { + let _this = this; + _this.adapter.enterChannel(channelUrl, () => { + _this.adapter.getMessageList((messageList) => { + _this.$spinner.remove(_this.$messageBoard.$content); + _this.$messageBoard.render(messageList, false, true); + + _this.adapter.createHandler((channel, message) => { + if (channel.url === channelUrl) { + _this.$messageBoard.render([message], false, false, true); + } + }); + }, true); + + if (callback) { + callback(); + } + }); + } + + exitChannel(callback) { + this.adapter.exitChannel(callback); + } + + loadGoogleFont() { + var wf = document.createElement('script'); + wf.src = + ('https:' == document.location.protocol ? 'https' : 'http') + + '://ajax.googleapis.com/ajax/libs/webfont/1.5.18/webfont.js'; + wf.type = 'text/javascript'; + wf.async = 'true'; + var s = document.getElementsByTagName('script')[0]; + s.parentNode.insertBefore(wf, s); + } +} + +window.liveChat = new LiveChat(); diff --git a/javascript/javascript-live-chat/src/js/elements/chat-board.js b/javascript/javascript-live-chat/src/js/elements/chat-board.js new file mode 100644 index 00000000..6ac2750d --- /dev/null +++ b/javascript/javascript-live-chat/src/js/elements/chat-board.js @@ -0,0 +1,12 @@ +'use strict'; +import Element from './element.js'; + +class ChatBoard extends Element { + constructor(parent) { + super(); + this.setClass('chat-board'); + parent.appendElement(this); + } +} + +export { ChatBoard as default }; diff --git a/javascript/javascript-live-chat/src/js/elements/element.js b/javascript/javascript-live-chat/src/js/elements/element.js new file mode 100644 index 00000000..91632248 --- /dev/null +++ b/javascript/javascript-live-chat/src/js/elements/element.js @@ -0,0 +1,297 @@ +'use strict'; + +import '../../scss/chat.scss'; + +class Element { + constructor(arg) { + this.supportedTags = ['div', 'span', 'input', 'label', 'button', 'img']; + this.supportedEvents = ['click', 'keydown', 'keyup', 'scroll', 'paste', 'change', 'focus', 'blur']; + if (!arg || typeof arg === 'string') { + let tag = this.supportedTags.indexOf(arg) >= 0 ? arg : 'div'; + this.$ = document.createElement(tag); + } else if (arg instanceof HTMLElement) { + this.$ = arg; + } + } + + setClass(...args) { + if (this.$) { + return (this.$.className = args.join(' ')); + } + } + + hasClass(className) { + if (this.$) { + if (this.$.classList) { + return this.$.classList.contains(className); + } else { + return new RegExp('(^| )' + className + '( |$)', 'gi').test(this.$.className); + } + } else { + return false; + } + } + + addClass(className) { + if (this.$) { + let classList = this.$.className.split(' '); + if (!(className in classList)) { + classList.push(className); + this.$.className = classList.join(' '); + } + } + return this.$; + } + + removeClass(className) { + if (this.$) { + if (this.$.classList) { + this.$.classList.remove(className); + } else { + this.$.className = this.$.className.replace( + new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), + '' + ); + } + } + return this.$; + } + + findByTag(tag) { + return this.$.querySelectorAll(tag); + } + + getTag() { + return this.$ ? this.$.tagName.toUpperCase() : ''; + } + + setStyle(style, value, unit = '') { + if (this.$) { + this.$.style[style] = value + unit; + } + } + + focus() { + if (this.$) { + this.$.focus(); + } + } + + blur() { + if (this.$) { + this.$.blur(); + } + } + + click() { + if (this.$) { + this.$.click(); + } + } + + attr(key, val) { + if (this.$) { + if (val !== undefined) { + this.$.setAttribute(key, val); + } + return this.$.getAttribute(key); + } + } + + removeAttr(key) { + if (this.$) { + this.$.removeAttribute(key); + } + } + + protectFromXSS(text) { + return text + .replace(/&/g, '&') + .replace(/#/g, '#') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, ''') + .replace(/\+/g, '+') + .replace(/-/g, '-') + .replace(/\(/g, '(') + .replace(/\)/g, ')') + .replace(/%/g, '%'); + } + + val(newVal, options) { + if (this.$) { + if (!options) options = {}; + + if (this.getTag() === 'INPUT') { + if (newVal !== undefined) { + this.$.value = newVal; + } + return this.$.value || ''; + } else { + if (newVal !== undefined) { + if (options.xssProtectionEnabled) { + newVal = this.protectFromXSS(newVal); + } + if (options.showEndOfLine) { + newVal = newVal.replace(/\n/g, '
'); + } + this.$.innerHTML = newVal; + } + return this.$.innerHTML; + } + } else { + return ''; + } + } + + appendContent(text, options) { + if (this.$) { + if (!options) options = {}; + if (options.xssProtectionEnabled) { + text = this.protectFromXSS(text); + } + if (options.showEndOfLine) { + text = text.replace(/\n/g, '
'); + } + this.val(this.val() + text); + } + return this.val(); + } + + enable() { + if (this.$) { + this.$.disabled = false; + } + } + + disable() { + if (this.$) { + this.$.disabled = true; + } + } + + first() { + return this.$.firstChild; + } + + last() { + return this.$.lastChild; + } + + children() { + return this.$.children; + } + + insertBefore(elem, before) { + if (this.$) { + if (elem instanceof Element) elem = elem.$; + if (before instanceof Element) before = before.$; + this.$.insertBefore(elem, before); + } + return this.$; + } + + appendElement(elem) { + if (this.$) { + if (elem instanceof HTMLElement) { + this.$.appendChild(elem); + } else { + this.$.appendChild(elem.$); + } + } + return this.$; + } + + replaceElement(from, to) { + if (this.$) { + if (from instanceof Element) from = from.$; + if (to instanceof Element) to = to.$; + this.$.replaceChild(to, from); + } + } + + removeElement(elem) { + if (this.$) { + if (elem instanceof HTMLElement) { + this.$.removeChild(elem); + } else { + this.$.removeChild(elem.$); + } + } + } + + removeFirst() { + if (this.$.children.length > 0) { + this.$.removeChild(this.$.firstChild); + } + } + + removeLast() { + if (this.$.children.length > 0) { + this.$.removeChild(this.$.lastChild); + } + } + + getFullWidth() { + let width = this.$.offsetWidth; + let style = getComputedStyle(this.$); + width += parseInt(style.marginLeft) + parseInt(style.marginRight); + return width; + } + + getFullHeight() { + let height = this.$.offsetHeight; + let style = getComputedStyle(this.$); + height += parseInt(style.marginTop) + parseInt(style.marginBottom); + return height; + } + + getScrollHeight() { + return this.$.scrollHeight; + } + + getScrollX() { + return this.$.scrollLeft; + } + + getScrollY() { + return this.$.scrollTop; + } + + scroll(x, y) { + this.scrollX(x); + this.scrollY(y); + } + + scrollX(x) { + this.$.scrollLeft = x; + } + + scrollY(y) { + this.$.scrollTop = y; + } + + scrollToTop() { + this.scrollY(0); + } + + scrollToBottom() { + this.scrollY(this.$.scrollHeight - this.$.clientHeight); + } + + isScrollBottom() { + return this.getScrollY() === this.$.scrollHeight - this.$.clientHeight; + } + + on(type, hdlr) { + if (this.$) { + type = this.supportedEvents.indexOf(type) >= 0 ? type : null; + if (type) { + this.$.addEventListener(type, hdlr); + } + } + } +} + +export { Element as default }; diff --git a/javascript/javascript-live-chat/src/js/elements/login-board.js b/javascript/javascript-live-chat/src/js/elements/login-board.js new file mode 100644 index 00000000..777c2a36 --- /dev/null +++ b/javascript/javascript-live-chat/src/js/elements/login-board.js @@ -0,0 +1,130 @@ +'use strict'; + +import Element from './element.js'; +import { KeyCode } from '../adapter.js'; + +const TEXT_INPUT_USER_ID = 'User ID'; +const TEXT_INPUT_USER_ID_PLACEHOLDER = 'Enter your user ID'; +const TEXT_INPUT_NICKNAME = 'Nickname'; +const TEXT_INPUT_NICKNAME_PLACEHOLDER = 'Enter your nickname'; +const TEXT_LOGIN_BTN = 'Start chat'; + +class LoginBoard extends Element { + constructor(board) { + super(board); + this.setClass('login-board'); + + const logo = new Element(); + logo.setClass('logo'); + this.appendElement(logo); + + const logoImage = new Element('img'); + logoImage.attr('src', 'https://dxstmhyqfqr1o.cloudfront.net/liveChat/icon-symbol-sb.svg'); + logo.appendElement(logoImage); + + const title = new Element(); + title.setClass('title'); + title.val('Sendbird Live chat sample'); + this.appendElement(title); + + let $userIdContainer = new Element(); + $userIdContainer.setClass('content', 'user-id'); + + let $userIdText = new Element(); + $userIdText.setClass('input-text'); + $userIdText.val(TEXT_INPUT_USER_ID); + $userIdContainer.appendElement($userIdText); + + let $userIdInput = (this.$userId = new Element('input')); + $userIdInput.setClass('input'); + $userIdInput.attr('placeholder', TEXT_INPUT_USER_ID_PLACEHOLDER); + $userIdContainer.appendElement($userIdInput); + this.appendElement($userIdContainer); + + let $nicknameContainer = new Element(); + $nicknameContainer.setClass('content', 'nickname'); + + let $nicknameText = new Element(); + $nicknameText.setClass('input-text'); + $nicknameText.val(TEXT_INPUT_NICKNAME); + $nicknameContainer.appendElement($nicknameText); + + let $nicknameInput = (this.$nickname = new Element('input')); + $nicknameInput.setClass('input'); + $nicknameInput.attr('placeholder', TEXT_INPUT_NICKNAME_PLACEHOLDER); + $nicknameContainer.appendElement($nicknameInput); + this.appendElement($nicknameContainer); + + let $login = (this.$login = new Element('button')); + $login.setClass('btn', 'login', 'disabled'); + $login.val(TEXT_LOGIN_BTN); + $login.attr('disabled', true); + this.appendElement($login); + + let updateLoginButtonState = () => { + if (this.$userId.val().trim() && this.$nickname.val().trim()) { + $login.removeClass('disabled'); + $login.removeAttr('disabled'); + } else { + $login.addClass('disabled'); + $login.attr('disabled', true); + } + }; + let userIdEventHandler = (event) => { + if (event && event.keyCode === KeyCode.ENTER) { + this.$nickname.focus(); + } else { + updateLoginButtonState(); + } + }; + let nicknameEventHandler = (event) => { + if (event && event.keyCode === KeyCode.ENTER) { + if (!this.$login.hasClass('disabled')) { + this.$login.click(); + } + } else { + updateLoginButtonState(); + } + }; + + this.$userId.on('keyup', userIdEventHandler); + this.$userId.on('change', userIdEventHandler); + this.$nickname.on('keyup', nicknameEventHandler); + this.$nickname.on('change', nicknameEventHandler); + } + + disable() { + this.$userId.disable(); + this.$nickname.disable(); + this.$login.addClass('disabled'); + this.$login.attr('disabled', true); + } + + reset() { + this.$userId.enable(); + this.$userId.val(''); + this.$nickname.enable(); + this.$nickname.val(''); + + this.$login.val(TEXT_LOGIN_BTN); + this.toggle(false); + } + + toggle(isEnabled) { + if (isEnabled || isEnabled === undefined) { + this.$login.removeClass('disabled'); + this.$login.removeAttr('disabled'); + this.$login.setStyle('cursor', ''); + } else { + this.$login.addClass('disabled'); + this.$login.attr('disabled', true); + this.$login.setStyle('cursor', 'default'); + } + } + + onLogin(hdlr) { + this.$login.on('click', hdlr); + } +} + +export { LoginBoard as default }; diff --git a/javascript/javascript-live-chat/src/js/elements/message-board.js b/javascript/javascript-live-chat/src/js/elements/message-board.js new file mode 100644 index 00000000..f34c34ee --- /dev/null +++ b/javascript/javascript-live-chat/src/js/elements/message-board.js @@ -0,0 +1,281 @@ +'use strict'; + +import Element from './element.js'; +import { KeyCode } from '../adapter.js'; + +const MESSAGE_PREFIX = ' : '; +const LAST_MESSAGE_YESTERDAY = 'YESTERDAY'; +const MORE_MESSAGE_BELOW = 'More message below.'; +const INPUT_MESSAGE_PLACEHOLDER = 'Type a message'; + +const MAX_MESSAGE_COUNT = 100; + +class MessageBoard extends Element { + constructor() { + super(); + this.setClass('message-board'); + + const top = new Element(); + top.setClass('top'); + this.appendElement(top); + + const topText = new Element(); + topText.setClass('top-text'); + topText.val('Live chat'); + top.appendElement(topText); + + const leave = new Element('button'); + leave.setClass('btn', 'leave'); + leave.setStyle('cursor', 'default'); + top.appendElement(leave); + + const leaveIcon = new Element('img'); + leaveIcon.setClass('leave-icon'); + leaveIcon.attr('src', 'https://dxstmhyqfqr1o.cloudfront.net/liveChat/icon-leave.svg'); + leave.appendElement(leaveIcon); + + const separator = new Element(); + separator.setClass('separator'); + this.appendElement(separator); + + let $content = new Element(); + $content.setClass('content'); + this.appendElement($content); + + let $contentInput = new Element(); + $contentInput.setClass('content-input'); + + let $input = new Element('input'); + $input.setClass('input'); + $input.attr('contenteditable', true); + $input.attr('placeholder', INPUT_MESSAGE_PLACEHOLDER); + + $input.on('focus', () => { + if (!$contentInput.hasClass('active')) $contentInput.addClass('active'); + }); + $input.on('blur', () => { + if ($contentInput.hasClass('active')) $contentInput.removeClass('active'); + }); + $input.on('keydown', (event) => { + this.toggleIcon(); + if (event.keyCode === KeyCode.ENTER) { + event.preventDefault(); + this.send.click(); + this.clearInput(); + } + }); + $input.on('keyup', () => { + this.toggleIcon(); + }); + $input.on('paste', (event) => { + event.stopPropagation(); + event.preventDefault(); + + const clipboardData = event.clipboardData || window.clipboardData; + $input.appendContent(clipboardData.getData('Text')); + }); + $contentInput.appendElement($input); + this.appendElement($contentInput); + + const send = new Element(); + send.setClass('btn', 'send'); + $contentInput.appendElement(send); + + const sendIcon = new Element('img'); + sendIcon.setClass('send-icon'); + sendIcon.attr('src', 'https://dxstmhyqfqr1o.cloudfront.net/liveChat/icon-send.svg'); + send.appendElement(sendIcon); + + this.leave = leave; + this.$content = $content; + this.$input = $input; + this.send = send; + this.reset(); + } + + getMessage() { + return this.$input.val().trim(); + } + + createMessageElement(message) { + let $item = new Element(); + $item.setClass('message-item'); + $item.attr('id', message.messageId); + + const profile = new Element(); + profile.setClass('profile'); + $item.appendElement(profile); + + const profileImage = new Element('img'); + profileImage.setClass('profile-image'); + profileImage.attr('src', message.sender.profileUrl); + profile.appendElement(profileImage); + + let $text = new Element(); + $text.setClass('message-text'); + + let $nickname = new Element('label'); + let nicknameColor = this.senderColor[message.sender.userId]; + if (!nicknameColor) { + nicknameColor = Math.floor(Math.random() * 6 + 1); + nicknameColor = nicknameColor < 10 ? '0' + nicknameColor.toString() : nicknameColor.toString(); + this.senderColor[message.sender.userId] = nicknameColor; + } + $nickname.setClass('nickname', 'nickname-color-' + nicknameColor); + $nickname.val(message.sender.nickname); + + $text.appendElement($nickname); + + const messageContent = new Element('span'); + messageContent.setClass('message-content'); + messageContent.appendContent(message.message, { + xssProtectionEnabled: true, + showEndOfLine: true, + }); + $text.appendElement(messageContent); + + $item.appendElement($text); + + // let $time = new Element(); + // $time.setClass('time'); + // $time.val(this.getTime(message)); + // $item.appendElement($time); + return $item; + } + + // getTime(message) { + // const months = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC']; + + // var _getDay = (val) => { + // let day = parseInt(val); + // let digit = day % 10; + // switch (digit) { + // case 1: + // return day + 'st'; + // case 2: + // return day + 'nd'; + // case 3: + // return day + 'rd'; + // default: + // return day + 'th'; + // } + // }; + + // var _checkTime = (val) => { + // return +val < 10 ? '0' + val : val; + // }; + + // if (message) { + // var _nowDate = new Date(); + // var _date = new Date(message.createdAt); + // if (_nowDate.getDate() - _date.getDate() === 1) { + // return LAST_MESSAGE_YESTERDAY; + // } else if ( + // _nowDate.getFullYear() === _date.getFullYear() && + // _nowDate.getMonth() === _date.getMonth() && + // _nowDate.getDate() === _date.getDate() + // ) { + // return _checkTime(_date.getHours()) + ':' + _checkTime(_date.getMinutes()); + // } else { + // return months[_date.getMonth()] + ' ' + _getDay(_date.getDate()); + // } + // } + // return ''; + // } + + render(messageList, isLoadingMore, scrollToBottom, newMessage) { + const isScrollBottom = this.$content.isScrollBottom(); + var moveScroll = 0; + for (let i in messageList) { + let message = messageList[i]; + if (message.isUserMessage()) { + let $item = this.createMessageElement(message); + if (isLoadingMore) { + let firstChild = this.$content.first(); + this.$content.insertBefore($item, firstChild); + } else { + this.$content.appendElement($item); + } + moveScroll += $item.getFullHeight(); + } else { + // put code here for other message type + } + } + + if (isLoadingMore) { + this.$content.scrollY(moveScroll); + } + + if (scrollToBottom) { + this.$content.scrollToBottom(); + } else if (isScrollBottom) { + this.$content.scrollToBottom(); + this.clearOverflowedMessages(); + } else if (newMessage) { + this.createBottomBar(); + } + } + + reset() { + this.senderColor = {}; + } + + toggleIcon() { + if (this.$input.val() && this.$input.val().length > 0) { + if (!this.send.hasClass('active')) { + this.send.addClass('active'); + } + } else { + this.send.removeClass('active'); + } + } + + clearInput() { + let items = this.$input.findByTag('div'); + for (let i = 0; i < items.length; i++) { + items[i].remove(); + } + this.$input.val(''); + this.toggleIcon(); + } + + createBottomBar() { + let _this = this; + let $btn = new Element(); + $btn.setClass('btn', 'scroll-to-bottom'); + // $btn.val(MORE_MESSAGE_BELOW); + $btn.on('click', () => { + _this.$content.scrollToBottom(); + _this.removeBottomBar(); + }); + + const image = new Element('img'); + image.setClass('icon'); + image.attr('src', 'https://dxstmhyqfqr1o.cloudfront.net/liveChat/icon-chevron-down.svg'); + $btn.appendElement(image); + + if (!this.$bottom) { + this.appendElement($btn); + this.$bottom = $btn; + } + } + + removeBottomBar() { + if (this.$bottom) { + this.removeElement(this.$bottom); + this.$bottom = null; + } + } + + clearOverflowedMessages() { + let $messages = this.$content.children(); + let overCount = $messages.length - MAX_MESSAGE_COUNT; + if (overCount > 0) { + for (let i = 0; i < overCount; i++) { + this.$content.removeFirst(); + } + } + } +} + +export { MessageBoard as default }; diff --git a/javascript/javascript-live-chat/src/js/elements/spinner.js b/javascript/javascript-live-chat/src/js/elements/spinner.js new file mode 100644 index 00000000..8a8b6805 --- /dev/null +++ b/javascript/javascript-live-chat/src/js/elements/spinner.js @@ -0,0 +1,28 @@ +'use strict'; + +import Element from './element.js'; + +const SPINNER_COUNT = 3; + +class Spinner extends Element { + constructor() { + super(); + this.setClass('sb-spinner'); + for(let i = 0 ; i < SPINNER_COUNT ; i++) { + this.appendElement(new Element()); + } + } + + attachTo($target) { + $target.val(""); + $target.appendElement(this); + } + + remove($target) { + if ($target.first()) { + $target.removeElement(this); + } + } +} + +export { Spinner as default }; diff --git a/web-live-chat/src/scss/_animation.scss b/javascript/javascript-live-chat/src/scss/_animation.scss similarity index 100% rename from web-live-chat/src/scss/_animation.scss rename to javascript/javascript-live-chat/src/scss/_animation.scss diff --git a/web-live-chat/src/scss/_icons.scss b/javascript/javascript-live-chat/src/scss/_icons.scss similarity index 100% rename from web-live-chat/src/scss/_icons.scss rename to javascript/javascript-live-chat/src/scss/_icons.scss diff --git a/web-live-chat/src/scss/_mixins.scss b/javascript/javascript-live-chat/src/scss/_mixins.scss similarity index 100% rename from web-live-chat/src/scss/_mixins.scss rename to javascript/javascript-live-chat/src/scss/_mixins.scss diff --git a/javascript/javascript-live-chat/src/scss/_variables.scss b/javascript/javascript-live-chat/src/scss/_variables.scss new file mode 100644 index 00000000..6ae5729f --- /dev/null +++ b/javascript/javascript-live-chat/src/scss/_variables.scss @@ -0,0 +1,64 @@ +// Color +$color-white: #FFFFFF !default; +$color-gray: #B7BFCC !default; + +// $color-message-nickname-01: #EA4130 !default; +// $color-message-nickname-02: #DF1962 !default; +// $color-message-nickname-03: #AB29CC !default; +// $color-message-nickname-04: #6634CC !default; +// $color-message-nickname-05: #3949BF !default; +// $color-message-nickname-06: #4097F6 !default; +// $color-message-nickname-07: #40BCD5 !default; +// $color-message-nickname-08: #2F9688 !default; +// $color-message-nickname-09: #5AAF4B !default; +// $color-message-nickname-10: #90C341 !default; +// $color-message-nickname-11: #D99100 !default; +// $color-message-nickname-12: #F79700 !default; +$color-message-nickname-01: #5959D3 !default; +$color-message-nickname-02: #007D69 !default; +$color-message-nickname-03: #E87021 !default; +$color-message-nickname-04: #C8485E !default; +$color-message-nickname-05: #8012B3 !default; +$color-message-nickname-06: #6210C8 !default; + +$color-text-message: #000000 !default; +$color-text-title: #333333 !default; +$color-text-input: #8090B4 !default; + +$color-more-message-background: #7B53EF !default; +$color-more-message-background-hover: #6440C4 !default; +$color-more-message-background-active: #4D2AA6 !default; + +$color-background-gray: #F6F8FA !default; +$color-border-top: #E5E5E5 !default; +$color-border-bottom: rgba(0, 0, 0, .38) !default; +$color-border-input: rgba(0, 0, 0, .24) !default; +$color-border-input-focus: #742DDD !default; + +// $color-input-background: #F8F9FA !default; +$color-input-text: rgba(0, 0, 0, .88) !default; +$color-input-shadow: #BDB0FF !default; +$color-input-placeholder: rgba(0, 0, 0, .38) !default; + +$color-box-shadow: #BDB0DD !default; + +$color-link-text: #319EDE !default; + +$color-spinner-default: #A5B3CD !default; + +$color-button-spinner: #FFFFFF !default; +// $color-button-border: #38B349 !default; +// $color-button-border-disabled: #95D296 !default; +$color-button-background: #742DDD !default; +$color-button-background-hover: #5813C1 !default; +$color-button-background-active: #3F0694 !default; +// $color-button-background-disabled: #98DC99 !default; + +$color-login-title: rgba(0, 0, 0, .88) !default; + +// Font +$font-family-default: 'OpenSans'; +$font-weight-default: 400; + +$content-message-input-default: 'Type a Message'; +$content-message-input-empty: ''; diff --git a/javascript/javascript-live-chat/src/scss/chat.scss b/javascript/javascript-live-chat/src/scss/chat.scss new file mode 100644 index 00000000..fcc895e4 --- /dev/null +++ b/javascript/javascript-live-chat/src/scss/chat.scss @@ -0,0 +1,430 @@ +@import "variables"; +@import "mixins"; +@import "animation"; +@import "icons"; + +#sb_chat { + font-family: $font-family-default !important; + font-weight: $font-weight-default !important; + -webkit-font-smoothing: antialiased !important; + + // Spinner + .sb-spinner { + @include reset(); + width: 100%; + text-align: center; + + div { + @include reset(); + display: inline-block; + width: 12px; + height: 12px; + background-color: $color-spinner-default; + @include border-radius(50%); + @include sb-ani-spinner(); + + } + :nth-child(1) { + @include reset(); + @include animation-delay(-0.32s); + } + :nth-child(2) { + @include reset(); + margin: 0 6px; + @include animation-delay(-0.16s); + } + } + + // Btn + .sb-common-btn { + padding: 0 16px; + // border: 1px solid $color-button-border; + border: none; + background-color: $color-button-background; + color: $color-white; + cursor: pointer; + @include border-radius(4px); + // @include box-shadow(0 1px 2px rgba(0, 0, 0, 0.05), 0 1px rgba(255, 255, 255, 0.75)); + @include hover { + // @include box-shadow(0 1px 2px rgba(0, 0, 0, 0.25), 0 1px rgba(255, 255, 255, 0.75)); + background-color: $color-button-background-hover; + } + @include active { + background-color: $color-button-background-active; + } + } + .sb-common-btn.disabled { + cursor: default; + // background-color: $color-button-background-disabled; + // border: 1px solid $color-button-border-disabled; + // @include hover { + // @include box-shadow(0 1px 2px rgba(0, 0, 0, 0.05), 0 1px rgba(255, 255, 255, 0.75)); + // } + } + + // Board + .chat-board { + @include reset(); + // width: calc(100% - 2px); + height: 100%; + // padding-bottom: 16px; + background-color: $color-white; + // border: 1px solid $color-border-top; + border-radius: 4px; + + // & > .top { + // @include reset(); + // width: 100%; + // height: 50px; + // line-height: 50px; + // text-align: center; + // border-bottom: 1px solid $color-border-top; + // background-color: $color-background-gray; + // } + } + + // Login + .login-board { + @include reset(); + width: calc(100% - 32px); + padding: 0 16px; + + > .logo { + @include reset(); + text-align: center; + + > img { + margin-top: 40px; + width: 48px; + height: 48px; + object-fit: contain; + } + } + + > .title { + margin-top: 16px; + text-align: center; + font-size: 20px; + font-weight: bold; + letter-spacing: -0.08px; + color: #000000; + } + + > .content { + @include reset(); + + > .input-text { + @include reset(); + font-size: 12px; + color: $color-login-title; + padding-bottom: 6px; + } + + > .input { + @include reset(); + height: calc(100% - 20px); + width: calc(100% - 32px); + color: $color-input-text; + border: 1px solid $color-border-input; + // background-color: $color-input-background; + font-size: 14px; + padding: 10px 16px; + @include border-radius(4px); + @include focus { + outline: none; + border: 1px solid $color-border-input-focus; + // @include box-shadow(0 0 4px $color-input-shadow); + } + } + } + > .user-id { + margin-top: 32px; + } + > .user-id::placeholder { + color: rgba(0, 0, 0, .38); + } + > .nickname { + margin-top: 20px; + } + > .nickname::placeholder { + color: rgba(0, 0, 0, .38); + } + + > .btn.login { + @include reset(); + @extend .sb-common-btn; + width: 100%; + height: 40px; + text-align: center; + margin: 32px auto 0 auto; + transition: background-color .2s; + + > .sb-spinner { + height: 16px; + > div { + width: 8px; + height: 8px; + background-color: $color-button-spinner; + } + :nth-child(2) { + margin: 0 4px; + } + } + } + > .btn.disabled { + background-color: rgba(0, 0, 0, .24); + } + } + + // Message + .message-board { + @include reset(); + width: 100%; + height: 100%; + overflow: hidden; + + > .top { + @include reset(); + padding: 16px; + text-align: center; + + > .top-text { + @include reset(); + display: inline-block; + height: 24px; + line-height: 24px; + font-size: 18px; + font-weight: 600; + color: black; + } + + > .btn.leave { + @include reset(); + @extend .sb-common-btn; + position: absolute; + top: 12px; + right: 16px; + padding: 4px; + background: none; + border: none; + transition: background-color .2s; + @include border-radius(4px); + @include hover { + background-color: #f0f0f0; + } + @include active { + background-color: #d9d9d9; + } + + > .leave-icon { + width: 24px; + height: 24px; + } + } + } + + > .separator { + width: 100%; + height: 1px; + background-color: #f0f0f0; + } + + > .content { + @include reset(); + width: calc(100% - 32px); + height: calc(100% - 56px - 1px - 80px); + padding: 0 16px; + overflow-x: hidden; + overflow-y: scroll; + + > .message-item { + @include reset(); + margin-top: 8px; + + > .profile { + @include reset(); + float: left; + + > .profile-image { + width: 24px; + height: 24px; + border-radius: 50%; + } + } + + > .message-text { + @include reset(); + // width: calc(100% - 68px); + // display: inline-block; + font-size: 14px; + line-height: 24px; + color: $color-text-message; + word-wrap: break-word; + + > .nickname { + @include reset(); + margin-left: 8px; + font-weight: 600; + } + + > .message-content { + @include reset(); + margin-left: 8px; + } + } + + // > .time { + // @include reset(); + // width: 66px; + // float: right; + // font-size: 11px; + // color: $color-gray; + // text-align: right; + // } + } + + > .sb-spinner { + height: 100%; + > div { + width: 12px; + height: 12px; + background-color: $color-spinner-default; + position: relative; + top: 50%; + @include transform-translate(0, -50%); + } + :nth-child(2) { + margin: 0 6px; + } + } + + } + + > .btn.scroll-to-bottom { + @include reset(); + width: 40px; + height: 40px; + position: relative; + left: calc(50% - 20px); + bottom: calc(80px - 16px + 4px + 40px); + background-color: $color-more-message-background; + @include border-radius(50%); + text-align: center; + font-size: 13px; + cursor: pointer; + @include box-shadow(0 2px 8px 0 rgba(0, 0, 0, .08), 0 4px 6px 0 rgba(0, 0, 0, .12)); + @include hover { + background-color: $color-more-message-background-hover; + } + @include active { + background-color: $color-more-message-background-active; + } + + > .icon { + position: absolute; + left: calc(50% - 12px); + top: calc(50% - 12px); + } + } + + > .content-input { + @include reset(); + width: calc(100% - 32px); + height: 48px; + margin: 0px; + padding: 16px; + background-color: $color-white; + position: relative; + overflow: hidden; + + > .input { + @include reset(); + width: calc(100% - 32px - 22px); + height: 20px; + min-height: 14px; + max-height: 39px; + overflow-y: scroll; + padding-right: calc(16px + 22px) !important; + padding: 14px 16px; + display: inline-block; + outline: none !important; + word-wrap: break-word; + background-color: $color-white; + color: $color-text-message; + font-size: 13px; + border: 1px solid $color-border-bottom; + @include border-radius(4px); + line-height: 7px; + } + > .input:empty::before { + width: 100%; + font-size: 13px; + content: $content-message-input-default; + color: $color-text-input; + } + > .input:focus:empty::before { + content: $content-message-input-empty; + } + + // > .icon { + // @include reset(); + // position: absolute; + // bottom: 15px; + // right: 20px; + // width: 19px; + // height: 19px; + // padding-left: 5px; + // @include icon($icon-send-btn); + // opacity: 0.3; + // cursor: default; + // } + // > .icon.active { + // opacity: 1; + // cursor: pointer; + // } + + > .btn.send { + @include reset(); + position: absolute; + top: 0px; + right: 0px; + margin: calc(16px + 1px + 14px + 10px - 11px); + filter: grayscale(100%); + opacity: .5; + transition: filter .2s, opacity .2s; + + > .send-icon { + width: 22px; + height: 22px; + } + } + > .btn.send.active { + filter: none; + opacity: 1; + } + } + > .content-input.active { + > .input { + border: 1px solid $color-border-input-focus; + @include border-radius(4px); + } + } + > .content-input::placeholder { + color: rgba(0, 0, 0, .38); + } + } + + .nickname-color-01 { color: $color-message-nickname-01; } + .nickname-color-02 { color: $color-message-nickname-02; } + .nickname-color-03 { color: $color-message-nickname-03; } + .nickname-color-04 { color: $color-message-nickname-04; } + .nickname-color-05 { color: $color-message-nickname-05; } + .nickname-color-06 { color: $color-message-nickname-06; } + // .nickname-color-07 { color: $color-message-nickname-07; } + // .nickname-color-08 { color: $color-message-nickname-08; } + // .nickname-color-09 { color: $color-message-nickname-09; } + // .nickname-color-10 { color: $color-message-nickname-10; } + // .nickname-color-11 { color: $color-message-nickname-11; } + // .nickname-color-12 { color: $color-message-nickname-12; } + +} diff --git a/javascript/javascript-live-chat/src/scss/mixins/_border-radius.scss b/javascript/javascript-live-chat/src/scss/mixins/_border-radius.scss new file mode 100644 index 00000000..95bb40a1 --- /dev/null +++ b/javascript/javascript-live-chat/src/scss/mixins/_border-radius.scss @@ -0,0 +1,59 @@ +@mixin border-radius($radius) { + border-radius: $radius; + -webkit-border-radius: $radius; + -moz-border-radius: $radius; + -ms-border-radius: $radius; + -o-border-radius: $radius; +} + +@mixin border-top-radius($radius) { + border-top-right-radius: $radius; + border-top-left-radius: $radius; + -webkit-border-top-right-radius: $radius; + -webkit-border-top-left-radius: $radius; + -moz-border-top-right-radius: $radius; + -moz-border-top-left-radius: $radius; + -ms-border-top-right-radius: $radius; + -ms-border-top-left-radius: $radius; + -o-border-top-right-radius: $radius; + -o-border-top-left-radius: $radius; +} + +@mixin border-right-radius($radius) { + border-bottom-right-radius: $radius; + border-top-right-radius: $radius; + -webkit-border-bottom-right-radius: $radius; + -webkit-border-top-right-radius: $radius; + -moz-border-bottom-right-radius: $radius; + -moz-border-top-right-radius: $radius; + -ms-border-bottom-right-radius: $radius; + -ms-border-top-right-radius: $radius; + -o-border-bottom-right-radius: $radius; + -o-border-top-right-radius: $radius; +} + +@mixin border-bottom-radius($radius) { + border-bottom-right-radius: $radius; + border-bottom-left-radius: $radius; + -webkit-border-bottom-right-radius: $radius; + -webkit-border-bottom-left-radius: $radius; + -moz-border-bottom-right-radius: $radius; + -moz-border-bottom-left-radius: $radius; + -ms-border-bottom-right-radius: $radius; + -ms-border-bottom-left-radius: $radius; + -o-border-bottom-right-radius: $radius; + -o-border-bottom-left-radius: $radius; +} + +@mixin border-left-radius($radius) { + border-bottom-left-radius: $radius; + border-top-left-radius: $radius; + -webkit-border-bottom-left-radius: $radius; + -webkit-border-top-left-radius: $radius; + -moz-border-bottom-left-radius: $radius; + -moz-border-top-left-radius: $radius; + -ms-border-bottom-left-radius: $radius; + -ms-border-top-left-radius: $radius; + -o-border-bottom-left-radius: $radius; + -o-border-top-left-radius: $radius; +} diff --git a/web-live-chat/src/scss/mixins/_box-shadow.scss b/javascript/javascript-live-chat/src/scss/mixins/_box-shadow.scss similarity index 100% rename from web-live-chat/src/scss/mixins/_box-shadow.scss rename to javascript/javascript-live-chat/src/scss/mixins/_box-shadow.scss diff --git a/javascript/javascript-live-chat/src/scss/mixins/_reset.scss b/javascript/javascript-live-chat/src/scss/mixins/_reset.scss new file mode 100644 index 00000000..eac43c4c --- /dev/null +++ b/javascript/javascript-live-chat/src/scss/mixins/_reset.scss @@ -0,0 +1,9 @@ +@mixin reset { + margin: 0; + padding: 0; + font-size: 100%; + line-height: 1; + width: auto; + height: auto; + box-sizing: initial; +} diff --git a/javascript/javascript-live-chat/src/scss/mixins/_state.scss b/javascript/javascript-live-chat/src/scss/mixins/_state.scss new file mode 100644 index 00000000..3b96e57c --- /dev/null +++ b/javascript/javascript-live-chat/src/scss/mixins/_state.scss @@ -0,0 +1,44 @@ +@mixin hover { + &:hover { @content; } +} + +@mixin plain-hover { + &, + &:hover { @content; } +} + +@mixin focus { + &:focus { @content; } +} + +@mixin plain-focus { + &, + &:focus { @content; } +} + +@mixin hover-focus { + &:hover, + &:focus { @content; } +} + +@mixin plain-hover-focus { + &, + &:hover, + &:focus { @content; } +} + +@mixin active { + &:active { @content; } +} + +@mixin after { + &::after { + @content + } +} + +@mixin before { + &::before { + @content + } +} diff --git a/javascript/javascript-live-chat/src/scss/mixins/_transform.scss b/javascript/javascript-live-chat/src/scss/mixins/_transform.scss new file mode 100644 index 00000000..026f6d1f --- /dev/null +++ b/javascript/javascript-live-chat/src/scss/mixins/_transform.scss @@ -0,0 +1,7 @@ +@mixin transform-translate($x, $y) { + -webkit-transform: translate($x, $y); + -moz-transform: translate($x, $y); + -ms-transform: translate($x, $y); + -o-transform: translate($x, $y); + transform: translate($x, $y); +} diff --git a/javascript/javascript-live-chat/webpack.config.js b/javascript/javascript-live-chat/webpack.config.js new file mode 100644 index 00000000..967d49f8 --- /dev/null +++ b/javascript/javascript-live-chat/webpack.config.js @@ -0,0 +1,59 @@ +'use strict'; +const path = require('path'); + +module.exports = { + entry: { + liveChat: ['babel-polyfill', './src/js/chat.js'], + }, + output: { + path: path.resolve(__dirname, 'dist'), + filename: '[name].SendBird.js', + publicPath: 'dist', + }, + devtool: 'eval-cheap-source-map', + devServer: { + publicPath: '/dist/', + compress: true, + port: 9000, + }, + module: { + rules: [ + { + // SCSS + test: /\.scss$/, + use: [ + { + loader: 'style-loader', + }, + { + loader: 'css-loader', + options: { + modules: { + localIdentName: '[local]', + }, + }, + }, + { + loader: 'sass-loader', + }, + ], + }, + { + // ESLint + enforce: 'pre', + test: /\.js$/, + exclude: /(node_modules|SendBird.min.js)/, + loader: 'eslint-loader', + options: { + failOnError: true, + }, + }, + { + // ES6 + test: /\.js($|\?)/i, + loader: 'babel-loader', + exclude: /(node_modules)/, + }, + ], + }, +}; diff --git a/javascript/javascript-widget/.babelrc b/javascript/javascript-widget/.babelrc new file mode 100644 index 00000000..a659ff45 --- /dev/null +++ b/javascript/javascript-widget/.babelrc @@ -0,0 +1,10 @@ +{ + "presets": [ + "@babel/preset-env" + ], + "env": { + "test": { + "presets": ["@babel/preset-env"] + } + } +} \ No newline at end of file diff --git a/web-widget/.eslintrc.js b/javascript/javascript-widget/.eslintrc.js similarity index 100% rename from web-widget/.eslintrc.js rename to javascript/javascript-widget/.eslintrc.js diff --git a/javascript/javascript-widget/CUSTOMIZE.md b/javascript/javascript-widget/CUSTOMIZE.md new file mode 100644 index 00000000..4052d80c --- /dev/null +++ b/javascript/javascript-widget/CUSTOMIZE.md @@ -0,0 +1,116 @@ +# Customize to ReactJS +This sample is not built on ReactJS. +If you want to use with ReactJS, you need to modify it to fit ReactJS and rebuild it using webpack. + +If you want to combine to ReactJS at the current condition, follow the instructions below. + +## Modify Widget Sample +### Modify `widget.js` +Remove `window.sbWidget = new SBWidget();` and add below at the last line in `widget.js`. +```javascript +// window.sbWidget = new SBWidget(); +var sbWidget = new SBWidget(); +window.sbWidget = sbWidget; +export default sbWidget; +``` + +### Modify `webpack.config.js` +Add `library` and `libraryTarget` in `output` field of `webpack.config.js`. +```javascript + output: { + path: path.resolve(__dirname + '/dist'), + filename: '[name].SendBird.js', + publicPath: 'dist', + library: 'SendBirdWidget', + libraryTarget: 'umd' + }, + optimization: { + minimize: false + }, +``` + +### Rebuild Widget Sample +Rebuild widget sample using webapck. +```bash +npm run build +``` + +## React App +### Create React App +Create new application using [Create-React-App](https://github.com/facebook/create-react-app#creating-an-app). +```bash +npm install -g create-react-app +create-react-app my-app + +cd my-app +``` + +And ejecting using `eject` command. +```bash +npm run eject +``` + +### Install SendBird and copy from widget sample +Install `SendBird JavaScript SDK` using npm. +```bash +npm install --save sendbird +``` + +`widget.SendBird.js` in widget sample copy to `my-app/src`. + +### Customizing ESLint +Create `.eslintrc` file to customize eslint rules. +```javascript +{ + "extends": "react-app", + "rules": { + "no-undef": "warn" + } +} +``` + +### Modify App.js and App.css +Change to the code below. +```javascript +import React, { Component } from 'react'; +import logo from './logo.svg'; +import './App.css'; +import SendBird from 'sendbird'; +import SendBirdWidget from './widget.SendBird'; + +class App extends Component { + componentDidMount() { + window.SendBird = SendBird; + SendBirdWidget.start('APP_ID'); // Sample APP_ID: '9DA1B1F4-0BE6-4DA8-82C5-2E81DAB56F23' + } + + render() { + return ( +
+
+ logo +

Welcome to React

+
+

+ To get started, edit src/App.js and save to reload. +

+
+
+ ); + } +} + +export default App; +``` + +Remove `text-align` in App.css +```css +.App { + /* text-align: center; */ +} +``` + +### Start ReactJS App +```bash +npm start +``` diff --git a/javascript/javascript-widget/README.md b/javascript/javascript-widget/README.md new file mode 100644 index 00000000..06f45c62 --- /dev/null +++ b/javascript/javascript-widget/README.md @@ -0,0 +1,136 @@ +# SendBird JavaScript Widget Sample +This is a sample chat widget built using using the [Sendbird SDK](https://github.com/sendbird/SendBird-SDK-JavaScript). It can be used to add a functional chat widget to any website. + + +## [Demo](https://sample.sendbird.com/widget/) + +You can try out a live demo from the link [here](https://sample.sendbird.com/widget/). Click on the button at the bottom-right corner of the webpage to try out the widget. Choose any 'User ID' and 'Nickname' to log in and participate in chats. + + +## Setup +1. The `body` must have a `div` element whose id is `sb_widget`. + +```html + +
+ +``` + +2. Import the [`Sendbird SDK`](https://github.com/sendbird/SendBird-SDK-JavaScript). +3. Import the `widget.SendBird.js` file. +```javascript + + +``` + + +## Customizing the widget +If you refresh your browser window, you need to reconnect to SendBird. To retain connection on browser refresh, you must implement an appropriate `event handler`. + +If you wish to issue an `access_token` for your user, modify the `connect function` in `src/sendbird.js`. + +> Require that you have Node v8.x+ installed. + +> `node-sass` package requires XCode developer tools (MacOS only) and Node.js version matching. If you have any trouble in the installation, see https://www.npmjs.com/package/node-sass. + +1. Install npm +```bash +npm install +``` + +2. Modify files. +```bash +npm run start:dev +``` + +3. Start sample. +```bash +npm start +``` + +## Advanced +### Connect other APP or Channel +If you want to connect other application, you need to change variable `appId` in `index.html`. + +```html +... + + + + + + +``` + +### Start with User connect +If you want to start this sample with user connect, you can using `startWithConnect()`. + +```html +... + + + + + + +``` + +### Show Channel +If you want to open chat, you can using `showChannel()`. + +```javascript +... +var channelUrl = ''; +sbWidget.showChannel(channelUrl); +... +``` + + +## File Structure +``` + |-- dist + |-- widget.SendBird.js - SendBird Widget Bundle file + |-- node_modules + |-- ... - (node packages) + |-- src + |-- js + |-- elements + |-- elements.js - elements root class + |-- spinner.js - spinner element + |-- widget-btn.js - widget button element + |-- popup.js - popup element + |-- list-board.js - channel list element + |-- chat-section.js - chat element + |-- consts.js - const variables + |-- utils.js - util functions + |-- sendbird.js - sendbird functions + |-- widget.js - widget functions + |-- scss + |-- mixins + |-- _border-radius.scss - border radius mixin + |-- _box-shadow.scss - box shadow mixin + |-- _state.scss - element state mixin + |-- _transform.scss - transform mixin + |-- _reset.scss - clean css mixin + |-- _mixins.scss - import mixin + |-- _variables.scss - css variables + |-- _animation.scss - animation + |-- _icons.scss - icon + |-- widget.scss - main css +|-- .eslintrc.js - lint setting +|-- webpack.config.js - webpack setting +|-- package.json - npm package +|-- SendBird.min.js - SendBird SDK +|-- index.html - sample file +|-- README.md +``` diff --git a/javascript/javascript-widget/index.html b/javascript/javascript-widget/index.html new file mode 100644 index 00000000..08081ba3 --- /dev/null +++ b/javascript/javascript-widget/index.html @@ -0,0 +1,41 @@ + + + + + + + Widget Sample + + + + + + +
Ver.0.18.0
+
+ +
+ + + + + + + + diff --git a/javascript/javascript-widget/package.json b/javascript/javascript-widget/package.json new file mode 100644 index 00000000..3b5f05ec --- /dev/null +++ b/javascript/javascript-widget/package.json @@ -0,0 +1,33 @@ +{ + "name": "Sample-JS-Web-Widget", + "version": "0.18.0", + "description": "Sendbird Widget Sample", + "main": "index.js", + "scripts": { + "start:dev": "./node_modules/.bin/webpack-dev-server", + "build": "./node_modules/.bin/webpack --mode production", + "start": "npm run build && node server.js" + }, + "author": "SendBird", + "license": "ISC", + "devDependencies": { + "@babel/core": "^7.2.0", + "@babel/preset-env": "^7.2.0", + "babel-eslint": "^10.0.1", + "babel-loader": "^8.0.4", + "babel-polyfill": "^6.26.0", + "css-loader": "^2.0.0", + "eslint": "^5.9.0", + "eslint-loader": "^2.1.1", + "node-sass": "^4.11.0", + "prettier": "^1.15.3", + "sass-loader": "^7.1.0", + "style-loader": "^0.23.1", + "webpack": "^4.27.1", + "webpack-cli": "^3.1.2", + "webpack-dev-server": "^3.1.11" + }, + "dependencies": { + "sendbird": "^3.0.129" + } +} diff --git a/javascript/javascript-widget/server.js b/javascript/javascript-widget/server.js new file mode 100644 index 00000000..487ba47b --- /dev/null +++ b/javascript/javascript-widget/server.js @@ -0,0 +1,14 @@ +const express = require('express'); +const app = express(); + +const PORT = 9000; + +app.use(express.static('dist')); +app.use(express.static('./')); + +app.get('/', function(req, res) { + res.sendfile('index.html'); +}); + +app.listen(PORT); +console.log(`[SERVER RUNNING] 127.0.0.1:${PORT}`); diff --git a/javascript/javascript-widget/src/js/adapter.js b/javascript/javascript-widget/src/js/adapter.js new file mode 100644 index 00000000..4dbd94d3 --- /dev/null +++ b/javascript/javascript-widget/src/js/adapter.js @@ -0,0 +1,386 @@ +import { MAX_COUNT } from "./consts.js"; +import { xssEscape } from "./utils.js"; + +import SendBird from "sendbird"; + +const GLOBAL_HANDLER = "GLOBAL_HANDLER"; +const GET_MESSAGE_LIMIT = 20; + +class SendBirdAdapter { + constructor(appId) { + this.sb = new SendBird({ + appId: appId + }); + this.channelListQuery = null; + this.userListQuery = null; + } + + reset() { + this.channelListQuery = null; + this.userListQuery = null; + this.sb.removeChannelHandler(GLOBAL_HANDLER); + } + + isConnected() { + return !!this.sb.currentUser; + } + + connect(userId, nickname, action) { + this.sb.connect(userId.trim(), (user, error) => { + if (error) { + console.error(error); + return; + } + this.sb.updateCurrentUserInfo(nickname.trim(), "", (response, error) => { + if (error) { + console.error(error); + return; + } + action(); + }); + }); + } + + disconnect(action) { + if (this.isConnected()) { + this.sb.disconnect(() => { + action(); + }); + } + } + + isCurrentUser(user) { + return this.sb.currentUser.userId == user.userId; + } + + /* + Channel + */ + getChannelList(action) { + if (!this.channelListQuery) { + this.channelListQuery = this.sb.GroupChannel.createMyGroupChannelListQuery(); + this.channelListQuery.includeEmpty = true; + this.channelListQuery.limit = 20; + } + if (this.channelListQuery.hasNext && !this.channelListQuery.isLoading) { + this.channelListQuery.next(function(channelList, error) { + if (error) { + console.error(error); + return; + } + action(channelList); + }); + } + } + + getChannelInfo(channelUrl, action) { + this.sb.GroupChannel.getChannel(channelUrl, function(channel, error) { + if (error) { + console.error(error); + return; + } + action(channel); + }); + } + + createNewChannel(userIds, action) { + this.sb.GroupChannel.createChannelWithUserIds( + userIds, + true, + "", + "", + "", + function(channel, error) { + if (error) { + console.error(error); + return; + } + action(channel); + } + ); + } + + inviteMember(channel, userIds, action) { + channel.inviteWithUserIds(userIds, (response, error) => { + if (error) { + console.error(error); + return; + } + action(); + }); + } + + channelLeave(channel, action) { + channel.leave((response, error) => { + if (error) { + console.error(error); + return; + } + action(); + }); + } + + /* + Message + */ + getTotalUnreadCount(action) { + this.sb.GroupChannel.getTotalUnreadMessageCount(unreadCount => { + action(unreadCount); + }); + } + + getMessageList(channelSet, action) { + if (!channelSet.query) { + channelSet.query = channelSet.channel.createPreviousMessageListQuery(); + } + if (channelSet.query.hasMore && !channelSet.query.isLoading) { + channelSet.query.load(GET_MESSAGE_LIMIT, false, function( + messageList, + error + ) { + if (error) { + console.error(error); + return; + } + action(messageList); + }); + } + } + + sendTextMessage(channel, textMessage, action) { + channel.sendUserMessage(textMessage, (message, error) => { + if (error) { + return; + } + action(message); + }); + } + + sendFileMessage(channel, file, action) { + let thumbSize = [ + { + maxWidth: 160, + maxHeight: 160 + } + ]; + channel.sendFileMessage(file, "", "", thumbSize, (message, error) => { + if (error) { + console.error(error); + return; + } + action(message); + }); + } + + _loadUserListFilter ( + userListQuery, + channelUrl, + prevUsers, + resolve, + reject + ) { + if (!userListQuery.hasNext) { + return resolve(prevUsers); + } + return userListQuery + .next() + .then(users => { + if (channelUrl) { + return this.sb.GroupChannel.getChannel(channelUrl) + .then(channel => { + const channelMemberIds = channel.members.map(member => { + return member.userId; + }); + const list = users.filter(user => { + return channelMemberIds.indexOf(user.userId) < 0; + }); + const filteredUsers = [...prevUsers, ...list]; + if (filteredUsers.length < userListQuery.limit / 2) { + return this._loadUserListFilter( + userListQuery, + channelUrl, + filteredUsers, + resolve, + reject + ); + } else { + resolve(filteredUsers); + } + }) + .catch(() => { + resolve([...users, ...prevUsers]); + }); + } else { + resolve([...users, ...prevUsers]); + } + }) + .catch(() => { + resolve(prevUsers); + }); + } + /** + * + * #################### SECURITY TIPS #################### + * Before launching, you should review "Allow retrieving user list from SDK" under ⚙️ Sendbird Dashboard ->Settings -> Security. + * It's turned on at first to simplify running samples and implementing your first code. + * Most apps will want to disable "Allow retrieving user list from SDK" as that could possibly expose user information + * #################### SECURITY TIPS #################### + * + */ + getUserList(channelUrl, cb) { + if(!this.userListQuery) { + this.userListQuery = this.sb.createApplicationUserListQuery(); + this.userListQuery.limit = 30; + } + return new Promise((resolve, reject) => { + const users = []; + return this._loadUserListFilter( + this.userListQuery, + channelUrl, + users, + resolve, + reject + ); + }) + .then(userList => { + cb(userList); + }) + .catch(error => { + console.error(error); + cb([]); + }); + } + + /* + Handler + */ + createHandlerGlobal(...args) { + let messageReceivedFunc = args[0]; + let messageUpdatedFunc = args[1]; + let messageDeletedFunc = args[2]; + let ChannelChangedFunc = args[3]; + let typingStatusFunc = args[4]; + let readReceiptFunc = args[5]; + let userLeftFunc = args[6]; + let userJoinFunc = args[7]; + + let channelHandler = new this.sb.ChannelHandler(); + channelHandler.onMessageReceived = function(channel, message) { + messageReceivedFunc(channel, message); + }; + channelHandler.onMessageUpdated = function(channel, message) { + messageUpdatedFunc(channel, message); + }; + channelHandler.onMessageDeleted = function(channel, messageId) { + messageDeletedFunc(channel, messageId); + }; + channelHandler.onChannelChanged = function(channel) { + ChannelChangedFunc(channel); + }; + channelHandler.onTypingStatusUpdated = function(channel) { + typingStatusFunc(channel); + }; + channelHandler.onReadReceiptUpdated = function(channel) { + readReceiptFunc(channel); + }; + channelHandler.onUserLeft = function(channel, user) { + userLeftFunc(channel, user); + }; + channelHandler.onUserJoined = function(channel, user) { + userJoinFunc(channel, user); + }; + this.sb.addChannelHandler(GLOBAL_HANDLER, channelHandler); + } + + /* + Info + */ + getNicknamesString(channel) { + let nicknameList = []; + let currentUserId = this.sb.currentUser.userId; + channel.members.forEach(function(member) { + if (member.userId != currentUserId) { + nicknameList.push(xssEscape(member.nickname)); + } + }); + return nicknameList.toString(); + } + + getMemberCount(channel) { + return channel.memberCount > 9 ? MAX_COUNT : channel.memberCount.toString(); + } + + getLastMessage(channel) { + if (channel.lastMessage) { + return channel.lastMessage.isUserMessage() || + channel.lastMessage.isAdminMessage() + ? channel.lastMessage.message + : channel.lastMessage.name; + } + return ""; + } + + getMessageTime(message) { + const months = [ + "JAN", + "FEB", + "MAR", + "APR", + "MAY", + "JUN", + "JUL", + "AUG", + "SEP", + "OCT", + "NOV", + "DEC" + ]; + + var _getDay = val => { + let day = parseInt(val); + if (day == 1) { + return day + "st"; + } else if (day == 2) { + return day + "en"; + } else if (day == 3) { + return day + "rd"; + } else { + return day + "th"; + } + }; + + var _checkTime = val => { + return +val < 10 ? "0" + val : val; + }; + + if (message) { + const LAST_MESSAGE_YESTERDAY = "YESTERDAY"; + var _nowDate = new Date(); + var _date = new Date(message.createdAt); + if (_nowDate.getDate() - _date.getDate() == 1) { + return LAST_MESSAGE_YESTERDAY; + } else if ( + _nowDate.getFullYear() == _date.getFullYear() && + _nowDate.getMonth() == _date.getMonth() && + _nowDate.getDate() == _date.getDate() + ) { + return ( + _checkTime(_date.getHours()) + ":" + _checkTime(_date.getMinutes()) + ); + } else { + return months[_date.getMonth()] + " " + _getDay(_date.getDate()); + } + } + return ""; + } + + getMessageReadReceiptCount(channel, message) { + return channel.getReadReceipt(message); + } + + getChannelUnreadCount(channel) { + return channel.unreadMessageCount; + } +} + +export { SendBirdAdapter as default }; diff --git a/javascript/javascript-widget/src/js/consts.js b/javascript/javascript-widget/src/js/consts.js new file mode 100644 index 00000000..45aa50ab --- /dev/null +++ b/javascript/javascript-widget/src/js/consts.js @@ -0,0 +1,100 @@ +export const className = { + WIDGET_BTN: 'widget', + NOTIFICATION: 'notification', + + ACTIVE: 'active', + DISABLED: 'disabled', + + CHANNEL_BOARD: 'channel-board', + BOARD_TOP: 'board-top', + OPTION_MENU: 'option-menu', + OPTION_CONTENT: 'option-content', + + TITLE: 'title', + INPUT: 'input', + BTN: 'btn', + ITEM: 'item', + IMAGE: 'image', + TOP: 'top', + COUNT: 'count', + TIME: 'time', + UNREAD: 'unread', + + CONTENT: 'content', + LOGIN_FORM: 'login-form', + LOGIN_BTN: 'login-btn', + USER_ID: 'user-id', + NICKNAME: 'nickname', + + CHANNEL_LIST: 'channel-list', + CONTENT_TOP: 'content-top', + CONTENT_BOTTOM: 'content-bottom', + LAST_MESSAGE: 'last-message', + EMPTY_ITEM: 'empty-item', + + CHAT_SECTION: 'chat-section', + CHAT_BOARD: 'chat-board', + MESSAGE_CONTENT: 'message-content', + MESSAGE_LIST: 'message-list', + TYPING: 'typing', + TEXT: 'text', + PREVIEW_NAME: 'preview-name', + PREVIEW_TITLE: 'preview-title', + PREVIEW_DESCRIPTION: 'preview-description', + PREVIEW_IMAGE: 'preview-iamge', + FILE_MESSAGE: 'file-message', + FILE: 'file', + FILE_ICON: 'file-icon', + FILE_NAME: 'file-name', + FILE_DOWNLOAD: 'file-download', + FILE_TEXT: 'file-text', + MESSAGE_SET: 'message-set', + USER: 'user', + MESSAGE_ITEM: 'message-item', + MESSAGE: 'message', + USER_CONTENT: 'user-content', + NEW_CHAT_BTN: 'new-chat-btn', + USER_SELECT: 'user-select', + USER_ITEM: 'user-item', + LEAVE_POPUP: 'leave-popup', + LEAVE_BTN: 'leave-btn', + CANCEL_BTN: 'cancel-btn', + ADMIN_MESSAGE: 'admin-message', + + POPUP: 'popup', + MEMBERS: 'members', + INVITE: 'invite', + POPUP_BODY: 'popup-body', + POPUP_TOP: 'popup-top', + POPUP_CONTENT: 'popup-content', + POPUP_BOTTOM: 'popup-bottom', + INVITE_BTN: 'invite-btn', + IMAGE_ME: 'image-me', + + TOOLTIP: 'tooltip', + + IC_LOGIN: 'ic-login', + IC_CONNECTED: 'ic-connected', + IC_MINIMIZE: 'ic-minimize', + IC_OPTION: 'ic-option', + IC_NEW_CHAT: 'ic-new-chat', + IC_CLOSE: 'ic-close', + IC_MEMBERS: 'ic-members', + IC_INVITE: 'ic-invite', + IC_LEAVE: 'ic-leave', + + FADE_IN: 'sb-fade-in', + FADE_OUT: 'sb-fade-out', + SPINNER: 'sb-spinner' + +}; + +export const styleValue = { + CURSOR_INIT: '', + CURSOR_DEFAULT: 'default' +}; + +export const MAX_COUNT = '+9'; +export const MAX_FONT_SIZE = '11'; + +export const TYPE_STRING = 'string'; diff --git a/web-widget/src/js/elements/chat-section.js b/javascript/javascript-widget/src/js/elements/chat-section.js similarity index 75% rename from web-widget/src/js/elements/chat-section.js rename to javascript/javascript-widget/src/js/elements/chat-section.js index 47840028..ed34048e 100644 --- a/web-widget/src/js/elements/chat-section.js +++ b/javascript/javascript-widget/src/js/elements/chat-section.js @@ -1,6 +1,6 @@ import { className, MAX_COUNT } from '../consts.js'; import Element from './elements.js'; -import { show, hide, getFullHeight, removeClass } from '../utils.js'; +import { show, hide, getFullHeight, removeClass, xssEscape } from '../utils.js'; const EMPTY_STRING = ''; @@ -46,7 +46,7 @@ class ChatSection extends Element { responsiveSize(isMax, action) { if (isMax !== undefined) { - this.self.style.right = isMax ? CHAT_SECTION_RIGHT_MIN : CHAT_SECTION_RIGHT_MAX; + this.self.style.cssText += `right: ${isMax ? CHAT_SECTION_RIGHT_MIN : CHAT_SECTION_RIGHT_MAX}`; } action(); } @@ -57,8 +57,8 @@ class ChatSection extends Element { moveToFirstIndex(target) { let items = this._getListBoardArray(); - items.filter((item) => { - if (item.id == target.id) { + items.filter(item => { + if (item.id === target.id) { this.self.removeChild(item); } }); @@ -180,7 +180,7 @@ class ChatSection extends Element { removeMemberPopup() { let items = this.self.querySelectorAll('.' + className.CHAT_BOARD); - for (var i = 0 ; i < items.length ; i++) { + for (var i = 0; i < items.length; i++) { let item = items[i]; removeClass(item.memberBtn, className.ACTIVE); } @@ -188,7 +188,7 @@ class ChatSection extends Element { removeInvitePopup() { let items = this.self.querySelectorAll('.' + className.CHAT_BOARD); - for (var i = 0 ; i < items.length ; i++) { + for (var i = 0; i < items.length; i++) { let item = items[i]; removeClass(item.inviteBtn, className.ACTIVE); } @@ -208,7 +208,7 @@ class ChatSection extends Element { getChatBoard(channelUrl) { let items = this.self.querySelectorAll('.' + className.CHAT_BOARD); let targetBoard; - for (var i = 0 ; i < items.length ; i++) { + for (var i = 0; i < items.length; i++) { let item = items[i]; if (item.id == channelUrl) { targetBoard = item; @@ -222,7 +222,7 @@ class ChatSection extends Element { var items = this.self.querySelectorAll('.' + className.CHAT_BOARD); let chatBoard = this.getChatBoard(channelUrl); let index = -1; - for (var i = 0 ; i < items.length ; i++) { + for (var i = 0; i < items.length; i++) { if (items[i] == chatBoard) { index = i; break; @@ -290,7 +290,7 @@ class ChatSection extends Element { clearInputText(target, channelUrl) { let items = target.querySelectorAll(this.tagName.DIV); - for (var i = 0 ; i < items.length ; i++) { + for (var i = 0; i < items.length; i++) { let item = items[i]; item.remove(); } @@ -321,11 +321,8 @@ class ChatSection extends Element { responsiveHeight(channelUrl) { let targetBoard = this.getChatBoard(channelUrl); let messageContent = targetBoard.messageContent; - let changeHeight = (getFullHeight(targetBoard.typing) + getFullHeight(targetBoard.input)); - this._setHeight( - messageContent, - (MESSAGE_CONTENT_HEIGHT_DEFAULT - (changeHeight - MESSAGE_INPUT_HEIGHT_DEFAULT)) - ); + let changeHeight = getFullHeight(targetBoard.typing) + getFullHeight(targetBoard.input); + this._setHeight(messageContent, MESSAGE_CONTENT_HEIGHT_DEFAULT - (changeHeight - MESSAGE_INPUT_HEIGHT_DEFAULT)); } showTyping(channel, spinner) { @@ -337,36 +334,42 @@ class ChatSection extends Element { } else { let typingUser = channel.getTypingMembers(); spinner.insert(typing); - this._addContent(typing, (typingUser.length > 1) ? MESSAGE_TYPING_SEVERAL : typingUser[0].nickname + MESSAGE_TYPING_MEMBER); + this._addContent( + typing, + typingUser.length > 1 ? MESSAGE_TYPING_SEVERAL : xssEscape(typingUser[0].nickname) + MESSAGE_TYPING_MEMBER + ); show(typing); } } - setImageSize(target, message) { - var imageResize = (imageTarget, width, height) => { - let scaleWidth = IMAGE_MAX_SIZE / width; - let scaleHeight = IMAGE_MAX_SIZE / height; + _imageResize(imageTarget, width, height) { + let scaleWidth = IMAGE_MAX_SIZE / width; + let scaleHeight = IMAGE_MAX_SIZE / height; - let scale = (scaleWidth <= scaleHeight) ? scaleWidth : scaleHeight; - if (scale > 1) { - scale = 1; - } + let scale = scaleWidth <= scaleHeight ? scaleWidth : scaleHeight; + if (scale > 1) { + scale = 1; + } - let resizeWidth = (width * scale); - let resizeHeight = (height * scale); + let resizeWidth = width * scale; + let resizeHeight = height * scale; - this._setBackgroundSize(imageTarget, resizeWidth + 'px ' + resizeHeight + 'px'); - this._setWidth(imageTarget, resizeWidth); - this._setHeight(imageTarget, resizeHeight); - }; + this._setBackgroundSize(imageTarget, resizeWidth + 'px ' + resizeHeight + 'px'); + this._setWidth(imageTarget, resizeWidth); + this._setHeight(imageTarget, resizeHeight); + return { resizeWidth: resizeWidth, resizeHeight: resizeHeight }; + } - this._setBackgroundImage(target, (message.thumbnails.length > 0) ? message.thumbnails[0].url : message.url); + setImageSize(target, message) { + this._setBackgroundImage(target, message.thumbnails.length > 0 ? message.thumbnails[0].url : message.url); if (message.thumbnails.length > 0) { - imageResize(target, message.thumbnails[0].real_width, message.thumbnails[0].real_height); + this._imageResize(target, message.thumbnails[0].real_width, message.thumbnails[0].real_height); } else { var img = new Image(); - img.addEventListener('load', (res) => { - res.path ? imageResize(target, res.path[0].width, res.path[0].height) : imageResize(target, res.target.width, res.target.height); + img.addEventListener('load', res => { + res.path + ? this._imageResize(target, res.path[0].width, res.path[0].height) + : this._imageResize(target, res.target.width, res.target.height); }); img.src = message.url; } @@ -377,7 +380,7 @@ class ChatSection extends Element { messageSet.id = message.messageId; this._setClass(messageSet, isCurrentUser ? [className.MESSAGE_SET, className.USER] : [className.MESSAGE_SET]); if (isContinue) { - messageSet.style.marginTop = MARGIN_TOP_MESSAGE; + messageSet.style.cssText += `margin-top: ${MARGIN_TOP_MESSAGE}`; } var senderImg = this.createDiv(); @@ -385,9 +388,9 @@ class ChatSection extends Element { var senderProfile = message.sender.profileUrl; if (isContinue) { senderProfile = ''; - senderImg.style.height = MESSAGE_NONE_IMAGE_HEIGHT; + senderImg.style.cssText += `height: ${MESSAGE_NONE_IMAGE_HEIGHT};`; } - senderImg.style.backgroundImage = 'url(' + senderProfile + ')'; + senderImg.style.cssText += `background-image: url(${senderProfile});`; messageSet.appendChild(senderImg); var messageContent = this.createDiv(); @@ -395,9 +398,9 @@ class ChatSection extends Element { var senderNickname = this.createDiv(); this._setClass(senderNickname, [className.NICKNAME]); - this._setContent(senderNickname, message.sender.nickname); + this._setContent(senderNickname, xssEscape(message.sender.nickname)); if (isContinue) { - senderNickname.style.display = DISPLAY_NONE; + senderNickname.style.cssText += `display: ${DISPLAY_NONE};`; } messageContent.appendChild(senderNickname); @@ -407,7 +410,45 @@ class ChatSection extends Element { var itemText = this.createDiv(); if (message.isUserMessage()) { this._setClass(itemText, [className.TEXT]); - this._setContent(itemText, message.message); + var urlexp = new RegExp( + '(http|https)://[a-z0-9-_]+(.[a-z0-9-_]+)+([a-z0-9-.,@?^=%&;:/~+#]*[a-z0-9-@?^=%&;/~+#])?', + 'i' + ); + var _message = message.message; + if (urlexp.test(_message)) { + _message = + '' + : '" target="_blank" style="color: #444444;">') + + _message + + ''; + if (message.customType === 'url_preview') { + let previewData = JSON.parse(message.data); + + var _siteName = this.createDiv(); + this._setClass(_siteName, [className.PREVIEW_NAME]); + this._setContent(_siteName, '@' + previewData.site_name); + + var _title = this.createDiv(); + this._setClass(_title, [className.PREVIEW_TITLE]); + this._setContent(_title, previewData.title); + + var _description = this.createDiv(); + this._setClass(_description, [className.PREVIEW_DESCRIPTION]); + this._setContent(_description, previewData.description); + + var _image = this.createDiv(); + this._setClass(_image, [className.PREVIEW_IMAGE]); + this._setBackgroundImage(_image, previewData.image); + + _message += '
' + _siteName.outerHTML + _title.outerHTML + _description.outerHTML + _image.outerHTML; + } + } else { + _message = xssEscape(_message); + } + this._setContent(itemText, _message); } else if (message.isFileMessage()) { if (message.type.match(/^image\/gif$/)) { this._setClass(itemText, [className.FILE_MESSAGE]); @@ -416,6 +457,27 @@ class ChatSection extends Element { image.src = message.url; this.setImageSize(image, message); itemText.appendChild(image); + } else if (message.type.match(/^video\/.+$/)) { + this._setClass(itemText, [className.FILE_MESSAGE]); + let video = this.createVideo(); + video.controls = true; + video.preload = 'auto'; + var resize = { resizeWidth: 160, resizeHeight: 160 }; + if (message.thumbnails && message.thumbnails.length > 0) { + video.poster = message.thumbnails[0].url; + resize = this._imageResize(video, message.thumbnails[0].real_width, message.thumbnails[0].real_height); + video.width = resize.resizeWidth; + video.height = resize.resizeHeight; + } else { + var _self = this; + video.addEventListener('loadedmetadata', function() { + resize = _self._imageResize(video, this.videoWidth, this.videoHeight); + video.width = resize.resizeWidth; + video.height = resize.resizeHeight; + }); + } + video.src = message.url; + itemText.appendChild(video); } else { this._setClass(itemText, [className.FILE_MESSAGE]); let file = this.createA(); @@ -434,7 +496,7 @@ class ChatSection extends Element { var fileName = this.createDiv(); this._setClass(fileName, [className.FILE_NAME]); - this._setContent(fileName, message.name); + this._setContent(fileName, xssEscape(message.name)); fileText.appendChild(fileName); var fileDownload = this.createDiv(); @@ -470,21 +532,21 @@ class ChatSection extends Element { createAdminMessageItem(message) { var admin = this.createDiv(); this._setClass(admin, [className.MESSAGE_SET, className.ADMIN_MESSAGE]); - this._setContent(admin, message.message); + this._setContent(admin, xssEscape(message.message)); return admin; } setUnreadCount(target, count) { count = parseInt(count); - this._setContent(target, (count > 9) ? MAX_COUNT : (count == 0) ? '' : count.toString()); - (count > 0) ? show(target, DISPLAY_TYPE_INLINE_BLOCK) : hide(target); + this._setContent(target, count > 9 ? MAX_COUNT : count == 0 ? '' : count.toString()); + count > 0 ? show(target, DISPLAY_TYPE_INLINE_BLOCK) : hide(target); } updateReadReceipt(channelSet, target) { var items = target.querySelectorAll('.' + className.MESSAGE_SET); - for (var j = 0 ; j < channelSet.message.length ; j++) { + for (var j = 0; j < channelSet.message.length; j++) { let message = channelSet.message[j]; - for (var i = 0 ; i < items.length ; i++) { + for (var i = 0; i < items.length; i++) { let item = items[i]; if (item.id == message.messageId) { this.setUnreadCount(item.unread, channelSet.channel.getReadReceipt(message)); @@ -553,7 +615,7 @@ class ChatSection extends Element { var userNickname = this.createDiv(); this._setClass(userNickname, [className.NICKNAME]); - this._setContent(userNickname, user.nickname); + this._setContent(userNickname, xssEscape(user.nickname)); userItem.appendChild(userNickname); li.appendChild(userItem); @@ -563,7 +625,7 @@ class ChatSection extends Element { getSelectedUserIds(target) { let items = target.querySelectorAll('.' + className.ACTIVE); var userIds = []; - for (var i = 0 ; i < items.length ; i++) { + for (var i = 0; i < items.length; i++) { let item = items[i]; userIds.push(item.getAttribute('data-user-id')); } @@ -585,7 +647,6 @@ class ChatSection extends Element { scrollToBottom(target) { target.scrollTop = target.scrollHeight - target.clientHeight; } - } export { ChatSection as default }; diff --git a/javascript/javascript-widget/src/js/elements/elements.js b/javascript/javascript-widget/src/js/elements/elements.js new file mode 100644 index 00000000..eaa75af5 --- /dev/null +++ b/javascript/javascript-widget/src/js/elements/elements.js @@ -0,0 +1,178 @@ +import '../../scss/widget.scss'; +import { removeClass, addClass } from '../utils.js'; +import { className, styleValue } from '../consts.js'; + +class Element { + constructor() { + this.tagName = { + DIV: 'div', + SPAN: 'span', + INPUT: 'input', + UL: 'ul', + LI: 'li', + TIME: 'time', + LABEL: 'label', + A: 'a', + IMG: 'img', + VIDEO: 'video' + }; + this.eventName = { + CLICK: 'click', + KEYDOWN: 'keydown', + KEYUP: 'keyup', + CHANGE: 'change', + SCROLL: 'scroll', + PASTE: 'paste' + }; + } + + /* + Create Elements + */ + createDiv() { + return document.createElement(this.tagName.DIV); + } + + createTime() { + return document.createElement(this.tagName.TIME); + } + + createA() { + return document.createElement(this.tagName.A); + } + + createImg() { + return document.createElement(this.tagName.IMG); + } + + createSpan() { + return document.createElement(this.tagName.SPAN); + } + + createLabel() { + return document.createElement(this.tagName.LABEL); + } + + createInput() { + return document.createElement(this.tagName.INPUT); + } + + createUl() { + return document.createElement(this.tagName.UL); + } + + createLi() { + return document.createElement(this.tagName.LI); + } + + createVideo() { + return document.createElement(this.tagName.VIDEO); + } + + _setClass(...args) { + args.reduce((target, classes) => { + return (target.className += classes.join(' ')); + }); + } + + _setContent(target, text) { + target.innerHTML = text; + } + + _addContent(target, text) { + target.innerHTML += text; + } + + _setBackgroundImage(target, url) { + target.style.cssText += `background-image: url(${url});`; + } + _setBackgroundSize(target, size) { + target.style.cssText += `background-size: ${size};`; + } + + _setFontSize(target, size) { + target.style.cssText += `font-size: ${size ? size + 'px' : null};`; + } + + _setHeight(target, height) { + target.style.cssText += `height: ${height}px;`; + } + + _setWidth(target, width) { + target.style.cssText += `width: ${width}px;`; + } + + _setRight(target, right) { + target.style.cssText += `right: ${right}px;`; + } + + _setDataset(target, name, data) { + target.setAttribute('data-' + name, data); + } + + _setClickEvent(...args) { + args.reduce((target, action) => { + target.addEventListener(this.eventName.CLICK, action); + }); + } + + _removeClickEvent(target, action) { + target.removeEventListener(this.eventName.CLICK, action); + } + + _setPasteEvent(...args) { + args.reduce((target, action) => { + target.addEventListener(this.eventName.PASTE, event => { + action(event); + }); + }); + } + + _setKeyupEvent(...args) { + args.reduce((target, action) => { + target.addEventListener(this.eventName.KEYUP, event => { + action(event); + }); + }); + } + + _setKeydownEvent(...args) { + args.reduce((target, action) => { + target.addEventListener(this.eventName.KEYDOWN, event => { + action(event); + }); + }); + } + + _setChangeEvent(...args) { + args.reduce((target, action) => { + target.addEventListener(this.eventName.CHANGE, () => { + action(); + }); + }); + } + + _setScrollEvent(...args) { + args.reduce((target, action) => { + target.addEventListener(this.eventName.SCROLL, () => { + action(); + }); + }); + } + + _isBottom(target, list) { + return target.scrollTop + target.offsetHeight >= list.offsetHeight; + } + + enabledToggle(target, isEnabled) { + if (isEnabled || isEnabled === undefined) { + removeClass(target, className.DISABLED); + target.style.cssText += `cursor: ${styleValue.CURSOR_INIT};`; + } else { + addClass(target, className.DISABLED); + target.style.cssText += `cursor: ${styleValue.CURSOR_DEFAULT};`; + } + } +} + +export { Element as default }; diff --git a/web-widget/src/js/elements/list-board.js b/javascript/javascript-widget/src/js/elements/list-board.js similarity index 98% rename from web-widget/src/js/elements/list-board.js rename to javascript/javascript-widget/src/js/elements/list-board.js index 3e3d8631..49e03937 100644 --- a/web-widget/src/js/elements/list-board.js +++ b/javascript/javascript-widget/src/js/elements/list-board.js @@ -1,4 +1,4 @@ -import { className, MAX_COUNT, MAX_FONT_ZISE } from '../consts.js'; +import { className, MAX_COUNT, MAX_FONT_SIZE } from '../consts.js'; import { show, hide, hasClass, removeClass, addClass, isEmptyString, removeWhiteSpace } from '../utils.js'; import Element from './elements.js'; @@ -7,7 +7,7 @@ const EMPTY_STRING = ''; const OPTION_TOOLTIP_TEXT = 'Log out'; const NEW_CHAT_TOOLTIP_TEXT = 'New Message'; -const TITLE_TOP_LOGIN = 'SendBird Widget'; +const TITLE_TOP_LOGIN = 'Sendbird Widget'; const TITLE_TOP_CHANNEL = 'Channel List'; const TITLE_LOGIN_USER_ID = 'USER ID'; const TITLE_LOGIN_NICKNAME = 'NICKNAME'; @@ -332,7 +332,7 @@ class ListBoard extends Element { setUnreadCount(target, count) { count = parseInt(count); this._setContent(target, (count > 9) ? MAX_COUNT : count.toString()); - this._setFontSize(target, (count > 9) ? MAX_FONT_ZISE : null); + this._setFontSize(target, (count > 9) ? MAX_FONT_SIZE : null); (count > 0) ? show(target) : hide(target); } diff --git a/web-widget/src/js/elements/popup.js b/javascript/javascript-widget/src/js/elements/popup.js similarity index 92% rename from web-widget/src/js/elements/popup.js rename to javascript/javascript-widget/src/js/elements/popup.js index 7e995d10..b5103ee1 100644 --- a/web-widget/src/js/elements/popup.js +++ b/javascript/javascript-widget/src/js/elements/popup.js @@ -1,6 +1,6 @@ import { className, MAX_COUNT } from '../consts.js'; import Element from './elements.js'; -import { addClass, show, hide } from '../utils.js'; +import { addClass, show, hide, xssEscape } from '../utils.js'; const EMPTY_STRING = ''; const TITLE_POPUP_MEMBER_LIST = 'Member List'; @@ -15,6 +15,7 @@ class Popup extends Element { super(); this._createMemberPopup(); this._createInvitePopup(); + this.inviteClickEventList = []; } reset() { @@ -33,6 +34,10 @@ class Popup extends Element { this._setContent(this.invitePopup.count, '0'); this._setContent(this.invitePopup.inviteBtn, TITLE_POPUP_INVITE_BTN); addClass(this.invitePopup.inviteBtn, className.DISABLED); + this.inviteClickEventList.forEach((obj) => { + this._removeClickEvent(obj.target, obj.action); + }); + this.inviteClickEventList = []; } showMemberPopup(chatSection, index) { @@ -116,7 +121,7 @@ class Popup extends Element { var userNickname = this.createDiv(); this._setClass(userNickname, [className.NICKNAME]); - this._setContent(userNickname, member.nickname); + this._setContent(userNickname, xssEscape(member.nickname)); div.appendChild(userNickname); li.appendChild(div); @@ -187,10 +192,12 @@ class Popup extends Element { }); } - addClickEvent(target, action) { + addClickEvent(target, action, options = {invite: false}) { + if(options.invite) { + this.inviteClickEventList.push({target, action}); + } this._setClickEvent(target, action); } - } export { Popup as default }; diff --git a/web-widget/src/js/elements/spinner.js b/javascript/javascript-widget/src/js/elements/spinner.js similarity index 100% rename from web-widget/src/js/elements/spinner.js rename to javascript/javascript-widget/src/js/elements/spinner.js diff --git a/web-widget/src/js/elements/widget-btn.js b/javascript/javascript-widget/src/js/elements/widget-btn.js similarity index 100% rename from web-widget/src/js/elements/widget-btn.js rename to javascript/javascript-widget/src/js/elements/widget-btn.js diff --git a/javascript/javascript-widget/src/js/utils.js b/javascript/javascript-widget/src/js/utils.js new file mode 100644 index 00000000..a86a237b --- /dev/null +++ b/javascript/javascript-widget/src/js/utils.js @@ -0,0 +1,184 @@ +const ANIMATION_EVENT = 'animationend'; +const ANIMATION_REGEX = 'sb-fade.*'; +const DISPLAY_NONE = 'none'; +const DISPLAY_BLOCK = 'block'; + +var hasClassRegex = (target, classNameRegex) => { + return new RegExp('(^| )' + classNameRegex + '( |$)', 'gi').test(target.className); +}; + +export function hide(target) { + if (target) { + if (hasClassRegex(target, ANIMATION_REGEX)) { + let hideAnimationEvent; + target.addEventListener( + ANIMATION_EVENT, + (hideAnimationEvent = function() { + target.style.cssText += `display: ${DISPLAY_NONE};`; + target.removeEventListener(ANIMATION_EVENT, hideAnimationEvent, false); + }) + ); + } else { + target.style.cssText += `display: ${DISPLAY_NONE};`; + } + } +} + +export function show(target, displayType) { + if (target) { + target.style.cssText += `display: ${displayType ? displayType : DISPLAY_BLOCK}`; + } +} + +export function hasClass(...args) { + return args.reduce((target, className) => { + if (target.classList) { + return target.classList.contains(className); + } else { + return new RegExp('(^| )' + className + '( |$)', 'gi').test(target.className); + } + }); +} + +export function addClass(...args) { + return args.reduce((target, className) => { + if (target.classList) { + if (!(className in target.classList)) { + target.classList.add(className); + } + } else { + if (target.className.indexOf(className) < 0) { + target.className += ' ' + className; + } + } + return target; + }); +} + +export function removeClass(...args) { + return args.reduce((target, className) => { + if (target.classList) { + target.classList.remove(className); + } else { + target.className = target.className.replace( + new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), + '' + ); + } + return target; + }); +} + +export function isEmptyString(target) { + return !!(target == null || target == undefined || target.length == 0); +} + +export function removeWhiteSpace(target) { + return target.replace(/ /g, ''); +} + +export function getFullHeight(target) { + var height = target.offsetHeight; + var style = getComputedStyle(target); + height += parseInt(style.marginTop) + parseInt(style.marginBottom); + return height; +} + +export function insertMessageInList(target, index, item) { + return target.splice(index, 0, item); +} + +export function getLastItem(target) { + return target.length < 1 ? null : target[target.length - 1]; +} + +export function xssEscape(target) { + if (typeof target === 'string') { + return target + .split('&') + .join('&') + .split('#') + .join('#') + .split('<') + .join('<') + .split('>') + .join('>') + .split('"') + .join('"') + .split("'") + .join(''') + .split('+') + .join('+') + .split('-') + .join('-') + .split('(') + .join('(') + .split(')') + .join(')') + .split('%') + .join('%'); + } else { + return target; + } +} + +export function createNotificationSound() { + var sound = document.createElement('audio'); + sound.style.cssText += `display: none;`; + sound.id = 'notifierSound'; + sound.src = 'https://dxstmhyqfqr1o.cloudfront.net/sound/SendBird-default.mp3'; + return sound; +} + +export function requestNotification() { + const userAgent = window.navigator.userAgent; + const msie = userAgent.indexOf('Trident/'); + const edge = userAgent.indexOf('Edge/'); + if (msie < 0 && edge < 0) { + if (window.Notification && Notification.permission !== 'granted') { + Notification.requestPermission(function(permission) { + if (Notification.permission !== permission) { + Notification.permission = permission; + } + }); + } + } +} + +export function setCookie(userId, nickname) { + var date = new Date(); + date.setDate(date.getDate() + 1); + var expires = date.toGMTString(); + document.cookie = 'sendbirdUserId=' + userId + ';expires=' + expires; + document.cookie = 'sendbirdNickname=' + nickname + ';expires=' + expires; +} + +export function getCookie() { + var sendbirdUserInfo = { + userId: '', + nickname: '' + }; + var cUserId = 'sendbirdUserId='; + var cNickname = 'sendbirdNickname='; + var cList = document.cookie.split(';'); + for (var i = 0; i < cList.length; i++) { + var c = cList[i]; + while (c.charAt(0) == ' ') { + c = c.substring(1); + } + if (c.indexOf(cUserId) === 0) { + sendbirdUserInfo['userId'] = c.substring(cUserId.length, c.length); + } else if (c.indexOf(cNickname) === 0) { + sendbirdUserInfo['nickname'] = c.substring(cNickname.length, c.length); + } + } + return sendbirdUserInfo; +} + +export function deleteCookie() { + const userInfo = getCookie(); + if (userInfo.userId) { + document.cookie = 'sendbirdUserId=' + userInfo.userId + ';expires=Thu, 01 Jan 1970 00:00:01 GMT;'; + document.cookie = 'sendbirdNickname=' + userInfo.nickname + ';expires=Thu, 01 Jan 1970 00:00:01 GMT;'; + } +} diff --git a/javascript/javascript-widget/src/js/widget.js b/javascript/javascript-widget/src/js/widget.js new file mode 100644 index 00000000..c08989b3 --- /dev/null +++ b/javascript/javascript-widget/src/js/widget.js @@ -0,0 +1,1030 @@ +import WidgetBtn from "./elements/widget-btn.js"; +import ListBoard from "./elements/list-board.js"; +import ChatSection from "./elements/chat-section.js"; +import Popup from "./elements/popup.js"; +import Spinner from "./elements/spinner.js"; +import SendBirdAdapter from "./adapter.js"; +import { + hide, + show, + addClass, + removeClass, + hasClass, + getFullHeight, + insertMessageInList, + getLastItem, + isEmptyString, + xssEscape, + createNotificationSound, + requestNotification, + setCookie, + getCookie, + deleteCookie +} from "./utils.js"; +import { className, TYPE_STRING, MAX_COUNT } from "./consts.js"; + +const WIDGET_ID = "sb_widget"; +const TIME_STRING_TODAY = "TODAY"; +const TIME_MESSAGE_TYPE = "time"; +const NEW_CHAT_BOARD_ID = "NEW_CHAT"; +const KEY_DOWN_ENTER = 13; +const KEY_DOWN_KR = 229; +const CHAT_BOARD_WIDTH = 300; +const ERROR_MESSAGE = 'Please create "sb_widget" element on first.'; +const EVENT_TYPE_CLICK = "click"; + +window.WebFontConfig = { + google: { families: ["Lato:400,700"] } +}; + +class SBWidget { + constructor() { } + + start(appId) { + this._getGoogleFont(); + this.widget = document.getElementById(WIDGET_ID); + if (this.widget) { + document.addEventListener(EVENT_TYPE_CLICK, event => { + this._initClickEvent(event); + }); + this._init(); + this._start(appId); + } else { + console.error(ERROR_MESSAGE); + } + } + + startWithConnect(appId, userId, nickname, callback) { + this._getGoogleFont(); + this.widget = document.getElementById(WIDGET_ID); + if (this.widget) { + document.addEventListener(EVENT_TYPE_CLICK, event => { + this._initClickEvent(event); + }); + this._init(); + this._start(appId); + this._connect(userId, nickname, callback); + } else { + console.error(ERROR_MESSAGE); + } + } + + _initClickEvent(event) { + var _checkPopup = function (_target, obj) { + if ( + obj === _target || + hasClass(_target, className.IC_MEMBERS) || + hasClass(_target, className.IC_INVITE) + ) { + return true; + } else { + var returnedCheck = false; + for (var i = 0; i < obj.childNodes.length; i++) { + returnedCheck = _checkPopup(_target, obj.childNodes[i]); + if (returnedCheck) break; + } + return returnedCheck; + } + }; + + if (!_checkPopup(event.target, this.popup.memberPopup)) { + this.closeMemberPopup(); + } + if (!_checkPopup(event.target, this.popup.invitePopup)) { + this.closeInvitePopup(); + } + } + + _init() { + this.spinner = new Spinner(); + + this.widgetBtn = new WidgetBtn(this.widget); + this.listBoard = new ListBoard(this.widget); + this.chatSection = new ChatSection(this.widget); + this.popup = new Popup(); + + this.activeChannelSetList = []; + this.extraChannelSetList = []; + + this.timeMessage = class TimeMessage { + constructor(date) { + this.time = date; + this.type = TIME_MESSAGE_TYPE; + } + isTimeMessage() { + return this.type == TIME_MESSAGE_TYPE; + } + }; + + requestNotification(); + this.notificationSound = createNotificationSound(); + } + + _getGoogleFont() { + var wf = document.createElement("script"); + wf.src = + ("https:" == document.location.protocol ? "https" : "http") + + "://ajax.googleapis.com/ajax/libs/webfont/1.5.18/webfont.js"; + wf.type = "text/javascript"; + wf.async = "true"; + var s = document.getElementsByTagName("script")[0]; + s.parentNode.insertBefore(wf, s); + } + + reset() { + this.extraChannelSetList = []; + for (var i = 0; i < this.activeChannelSetList.length; i++) { + let channelSet = this.activeChannelSetList[i]; + let targetBoard = this.chatSection.getChatBoard(channelSet.channel.url); + if (targetBoard) { + this.chatSection.closeChatBoard(targetBoard); + } + } + this.activeChannelSetList = []; + this.closePopup(); + + this.sb.reset(); + this.listBoard.reset(); + this.widgetBtn.reset(); + } + + responsiveChatSection(channelUrl, isShow) { + let _bodyWidth = document.getElementsByTagName("BODY")[0].offsetWidth - 360; + let maxSize = parseInt(_bodyWidth / CHAT_BOARD_WIDTH); + let currentSize = this.activeChannelSetList.length; + if (currentSize >= maxSize) { + let extraChannelSet = getLastItem(this.activeChannelSetList); + if (extraChannelSet) { + if (this.extraChannelSetList.indexOf(extraChannelSet.channel.url) < 0) { + this.extraChannelSetList.push(extraChannelSet.channel.url); + } + let chatBoard = this.chatSection.getChatBoard( + extraChannelSet.channel.url + ); + if (chatBoard) { + this.chatSection.closeChatBoard(chatBoard); + } + this.removeChannelSet(extraChannelSet.channel); + } + if (channelUrl) { + let idx = this.extraChannelSetList.indexOf(channelUrl); + if (idx > -1) { + this.extraChannelSetList.splice(idx, 1); + } + } + this.chatSection.setWidth(maxSize * CHAT_BOARD_WIDTH); + } else { + let popChannelUrl = this.extraChannelSetList.pop(); + if (popChannelUrl) { + this._connectChannel(popChannelUrl, true); + this.chatSection.setWidth((currentSize + 1) * CHAT_BOARD_WIDTH); + } else { + if (isShow) { + currentSize += 1; + } + this.chatSection.setWidth(currentSize * CHAT_BOARD_WIDTH); + } + } + } + + _start(appId) { + this.sb = new SendBirdAdapter(appId); + + this.popup.addCloseBtnClickEvent(() => { + this.closePopup(); + }); + + this.widgetBtn.addClickEvent(() => { + this.sb.isConnected() + ? this.listBoard.showChannelList() + : this.listBoard.showLoginForm(); + this.toggleBoard(true); + this.listBoard.addChannelListScrollEvent(() => { + this.getChannelList(); + }); + this.chatSection.responsiveSize( + false, + this.responsiveChatSection.bind(this) + ); + }); + + this.listBoard.addNewChatClickEvent(() => { + this.listBoard.hideLogoutBtn(); + + var chatBoard = this.chatSection.createChatBoard(NEW_CHAT_BOARD_ID); + this.responsiveChatSection(null, true); + + this.chatSection.createNewChatBoard(chatBoard); + this.chatSection.addClickEvent(chatBoard.startBtn, () => { + if (!hasClass(chatBoard.startBtn, className.DISABLED)) { + addClass(chatBoard.startBtn, className.DISABLED); + this.sb.userListQuery = null; + this.spinner.insert(chatBoard.startBtn); + let selectedUserIds = this.chatSection.getSelectedUserIds( + chatBoard.userContent + ); + this.sb.createNewChannel(selectedUserIds, channel => { + chatBoard.parentNode.removeChild(chatBoard); + this._connectChannel(channel.url, true); + this.listBoard.checkEmptyList(); + }); + } + }); + this.spinner.insert(chatBoard.userContent); + + this.sb.getUserList(null, userList => { + this.spinner.remove(chatBoard.userContent); + this.setUserList(chatBoard, userList); + }); + + this.chatSection.addClickEvent(chatBoard.closeBtn, () => { + this.chatSection.closeChatBoard(chatBoard); + this.closePopup(); + this.responsiveChatSection(); + }); + hide(chatBoard.leaveBtn); + hide(chatBoard.memberBtn); + hide(chatBoard.inviteBtn); + }); + + this.listBoard.addMinimizeClickEvent(() => { + this.listBoard.hideLogoutBtn(); + this.closePopup(); + this.toggleBoard(false); + this.chatSection.responsiveSize( + true, + this.responsiveChatSection.bind(this) + ); + }); + + this.listBoard.addLogoutClickEvent(() => { + this.sb.disconnect(() => { + deleteCookie(); + this.sb.reset(); + this.toggleBoard(false); + this.widgetBtn.toggleIcon(false); + this.listBoard.setOptionEventLock(false); + this.chatSection.reset(); + this.reset(); + }); + }); + + this.listBoard.addLoginClickEvent(() => { + if (!hasClass(this.listBoard.btnLogin, className.DISABLED)) { + this.spinner.insert(this.listBoard.btnLogin); + this.listBoard.enabledToggle(this.listBoard.btnLogin, false); + this.listBoard.userId.disabled = true; + this.listBoard.nickname.disabled = true; + + this._connect(this.listBoard.getUserId(), this.listBoard.getNickname()); + setCookie(this.listBoard.getUserId(), this.listBoard.getNickname()); + } + }); + this.listBoard.addKeyDownEvent(this.listBoard.nickname, event => { + if (event.keyCode == KEY_DOWN_ENTER) { + this.listBoard.btnLogin.click(); + } + }); + + const cookie = getCookie(); + if (cookie.userId) { + this._connect(cookie.userId, cookie.nickname); + this.listBoard.showChannelList(); + this.toggleBoard(true); + this.chatSection.responsiveSize( + false, + this.responsiveChatSection.bind(this) + ); + } + } + + _connect(userId, nickname, callback) { + this.sb.connect(userId, nickname, () => { + this.widgetBtn.toggleIcon(true); + + this.listBoard.showChannelList(); + this.spinner.insert(this.listBoard.list); + this.getChannelList(); + + this.sb.createHandlerGlobal( + (channel, message) => { + this.messageReceivedAction(channel, message); + }, + (channel, message) => { + this.messageUpdatedAction(channel, message); + }, + (channel, messageId) => { + this.messageDeletedAction(channel, messageId); + }, + channel => { + this.updateUnreadMessageCount(channel); + }, + channel => { + let targetBoard = this.chatSection.getChatBoard(channel.url); + if (targetBoard) { + let isBottom = this.chatSection.isBottom( + targetBoard.messageContent, + targetBoard.list + ); + this.chatSection.showTyping(channel, this.spinner); + this.chatSection.responsiveHeight(channel.url); + if (isBottom) { + this.chatSection.scrollToBottom(targetBoard.messageContent); + } + } + }, + channel => { + let targetBoard = this.chatSection.getChatBoard(channel.url); + if (targetBoard) { + var channelSet = this.getChannelSet(channel.url); + if (channelSet) { + this.chatSection.updateReadReceipt(channelSet, targetBoard); + } + } + }, + (channel, user) => { + if (this.sb.isCurrentUser(user)) { + let item = this.listBoard.getChannelItem(channel.url); + this.listBoard.list.removeChild(item); + this.listBoard.checkEmptyList(); + } else { + this.listBoard.setChannelTitle( + channel.url, + this.sb.getNicknamesString(channel) + ); + this.updateUnreadMessageCount(channel); + let targetChatBoard = this.chatSection.getChatBoard(channel.url); + if (targetChatBoard) { + this.updateChannelInfo(targetChatBoard, channel); + } + } + }, + (channel, _) => { + this.listBoard.setChannelTitle( + channel.url, + this.sb.getNicknamesString(channel) + ); + let targetChatBoard = this.chatSection.getChatBoard(channel.url); + if (targetChatBoard) { + this.updateChannelInfo(targetChatBoard, channel); + } + } + ); + + if (callback) callback(); + }); + } + + messageReceivedAction(channel, message) { + let target = this.listBoard.getChannelItem(channel.url); + if (!target) { + target = this.createChannelItem(channel); + this.listBoard.checkEmptyList(); + } + this.listBoard.addListOnFirstIndex(target); + + this.listBoard.setChannelLastMessage( + channel.url, + message.isFileMessage() + ? xssEscape(message.name) + : xssEscape(message.message) + ); + this.listBoard.setChannelLastMessageTime( + channel.url, + this.sb.getMessageTime(message) + ); + + let targetBoard = this.chatSection.getChatBoard(channel.url); + if (targetBoard) { + let isBottom = this.chatSection.isBottom( + targetBoard.messageContent, + targetBoard.list + ); + let channelSet = this.getChannelSet(channel.url); + let lastMessage = getLastItem(channelSet.message); + if (!channelSet.message.map(m => m.messageId).includes(message.messageId)) { + channelSet.message.push(message); + this.setMessageItem( + channelSet.channel, + targetBoard, + [message], + false, + isBottom, + lastMessage + ); + } + channel.markAsRead(); + this.updateUnreadMessageCount(channel); + } + if (!targetBoard) { + if ("Notification" in window) { + var notification = new Notification("New Message", { + body: message.isFileMessage() ? message.name : message.message, + icon: + "http://qnimate.com/wp-content/uploads/2014/07/web-notification-api-300x150.jpg" + }); + notification.onclick = function () { + window.focus(); + }; + this.notificationSound.play(); + } + } + } + + messageUpdatedAction(channel, message) { + let targetBoard = this.chatSection.getChatBoard(channel.url); + if (targetBoard) { + let channelSet = this.getChannelSet(channel.url); + let newMessages = channelSet.message.map(msg => { + if (msg.messageId === message.messageId) { + return message; + } else { + return msg; + } + }); + channelSet.message = newMessages; + + let lastMessage = getLastItem(channelSet.message); + if (lastMessage.messageId === message.messageId) { + let target = this.listBoard.getChannelItem(channel.url); + if (!target) { + target = this.createChannelItem(channel); + this.listBoard.checkEmptyList(); + } + this.listBoard.addListOnFirstIndex(target); + this.listBoard.setChannelLastMessage( + channel.url, + message.isFileMessage() + ? xssEscape(message.name) + : xssEscape(message.message) + ); + } + let updatedMessage = document + .getElementById(`${message.messageId}`) + .querySelector("div>div>div.text"); + if (updatedMessage) { + updatedMessage.innerHTML = message.message; + } + } + } + + messageDeletedAction(channel, messageId) { + let targetBoard = this.chatSection.getChatBoard(channel.url); + if (targetBoard) { + let channelSet = this.getChannelSet(channel.url); + let lastMessage = getLastItem(channelSet.message); + if (lastMessage.messageId.toString() === messageId.toString()) { + channelSet.message.pop(); + lastMessage = getLastItem(channelSet.message); + let target = this.listBoard.getChannelItem(channel.url); + if (!target) { + target = this.createChannelItem(channel); + this.listBoard.checkEmptyList(); + } + this.listBoard.addListOnFirstIndex(target); + this.listBoard.setChannelLastMessage( + channel.url, + lastMessage.isFileMessage() + ? xssEscape(lastMessage.name) + : xssEscape(lastMessage.message) + ); + } else { + let newMessages = channelSet.message.filter(msg => { + return msg.messageId.toString() !== messageId.toString(); + }); + channelSet.message = newMessages; + } + + let updatedMessage = document.getElementById(`${messageId}`); + updatedMessage.remove(); + } + } + + setUserList(target, userList) { + let userContent = target.userContent; + this.chatSection.createUserList(userContent); + for (var i = 0; i < userList.length; i++) { + let user = userList[i]; + if (!this.sb.isCurrentUser(user)) { + let item = this.chatSection.createUserListItem(user); + this.chatSection.addClickEvent(item, () => { + hasClass(item.select, className.ACTIVE) + ? removeClass(item.select, className.ACTIVE) + : addClass(item.select, className.ACTIVE); + let selectedUserCount = this.chatSection.getSelectedUserIds( + userContent.list + ).length; + this.chatSection.updateChatTop( + target, + selectedUserCount > 9 ? MAX_COUNT : selectedUserCount.toString(), + null + ); + selectedUserCount > 0 + ? removeClass(target.startBtn, className.DISABLED) + : addClass(target.startBtn, className.DISABLED); + }); + userContent.list.appendChild(item); + } + } + this.chatSection.addUserListScrollEvent(target, () => { + this.sb.getUserList(null, userList => { + this.setUserList(target, userList); + }); + }); + } + + getChannelList() { + let _list = this.listBoard.list; + let _spinner = this.spinner; + this.sb.getChannelList(channelList => { + if (_list.lastElementChild == _spinner.self) { + _spinner.remove(_list); + } + channelList.forEach(channel => { + let item = this.createChannelItem(channel); + _list.appendChild(item); + }); + this.updateUnreadMessageCount(); + this.listBoard.checkEmptyList(); + }); + } + + createChannelItem(channel) { + let item = this.listBoard.createChannelItem( + channel.url, + channel.coverUrl, + this.sb.getNicknamesString(channel), + this.sb.getMessageTime(channel.lastMessage), + this.sb.getLastMessage(channel), + this.sb.getChannelUnreadCount(channel) + ); + this.listBoard.addChannelClickEvent(item, () => { + this.closePopup(); + let channelUrl = item.getAttribute("data-channel-url"); + let openChatBoard = this.chatSection.getChatBoard(channelUrl); + if (!openChatBoard) { + var newChat = this.chatSection.getChatBoard(NEW_CHAT_BOARD_ID); + if (newChat) { + this.chatSection.closeChatBoard(newChat); + } + this._connectChannel(channelUrl); + } + }); + return item; + } + + closePopup() { + this.closeMemberPopup(); + this.closeInvitePopup(); + } + + closeMemberPopup() { + this.chatSection.removeMemberPopup(); + this.popup.closeMemberPopup(); + } + + closeInvitePopup() { + this.chatSection.removeInvitePopup(); + this.popup.closeInvitePopup(); + + var chatBoard = this.chatSection.getChatBoard(NEW_CHAT_BOARD_ID); + if (!chatBoard) { + this.sb.userListQuery = null; + } + } + + showChannel(channelUrl) { + this._connectChannel(channelUrl, false); + } + + _connectChannel(channelUrl, doNotCall) { + var chatBoard = this.chatSection.createChatBoard(channelUrl, doNotCall); + if (!doNotCall) { + this.responsiveChatSection(channelUrl, true); + } + this.chatSection.addClickEvent(chatBoard.closeBtn, () => { + this.chatSection.closeChatBoard(chatBoard); + this.closePopup(); + this.removeChannelSet(channelUrl); + this.responsiveChatSection(); + }); + this.chatSection.addClickEvent(chatBoard.leaveBtn, () => { + this.chatSection.addLeavePopup(chatBoard); + this.chatSection.setLeaveBtnClickEvent( + chatBoard.leavePopup.leaveBtn, + () => { + this.spinner.insert(chatBoard.leavePopup.leaveBtn); + addClass(chatBoard.leavePopup.leaveBtn, className.DISABLED); + let channelSet = this.getChannelSet(channelUrl); + if (channelSet) { + this.sb.channelLeave(channelSet.channel, () => { + chatBoard.removeChild(chatBoard.leavePopup); + removeClass(chatBoard.leavePopup.leaveBtn, className.DISABLED); + chatBoard.leavePopup = null; + chatBoard.closeBtn.click(); + }); + } else { + this.chatSection.closeChatBoard(chatBoard); + } + } + ); + }); + this.chatSection.addClickEvent(chatBoard.memberBtn, () => { + if (hasClass(chatBoard.memberBtn, className.ACTIVE)) { + this.closeMemberPopup(); + } else { + this.closeMemberPopup(); + this.closeInvitePopup(); + addClass(chatBoard.memberBtn, className.ACTIVE); + let index = this.chatSection.indexOfChatBord(channelUrl); + this.popup.showMemberPopup(this.chatSection.self, index); + let channelSet = this.getChannelSet(channelUrl); + this.popup.updateCount( + this.popup.memberPopup.count, + channelSet.channel.memberCount + ); + for (var i = 0; i < channelSet.channel.members.length; i++) { + let member = channelSet.channel.members[i]; + let item = this.popup.createMemberItem( + member, + false, + this.sb.isCurrentUser(member) + ); + this.popup.memberPopup.list.appendChild(item); + } + } + }); + this.chatSection.addClickEvent(chatBoard.inviteBtn, () => { + var _getUserList = (channel, loadmore) => { + this.sb.getUserList(channel.url, userList => { + if (!loadmore) { + this.spinner.remove(this.popup.invitePopup.list); + } + for (var i = 0; i < userList.length; i++) { + let user = userList[i]; + + let item = this.popup.createMemberItem(user, true); + this.popup.addClickEvent(item, () => { + hasClass(item.select, className.ACTIVE) + ? removeClass(item.select, className.ACTIVE) + : addClass(item.select, className.ACTIVE); + let selectedUserCount = this.popup.getSelectedUserIds( + this.popup.invitePopup.list + ).length; + this.popup.updateCount( + this.popup.invitePopup.count, + selectedUserCount + ); + selectedUserCount > 0 + ? removeClass( + this.popup.invitePopup.inviteBtn, + className.DISABLED + ) + : addClass( + this.popup.invitePopup.inviteBtn, + className.DISABLED + ); + }); + this.popup.invitePopup.list.appendChild(item); + } + }); + }; + + if (hasClass(chatBoard.inviteBtn, className.ACTIVE)) { + this.closeInvitePopup(); + } else { + this.closeInvitePopup(); + this.closeMemberPopup(); + addClass(chatBoard.inviteBtn, className.ACTIVE); + let index = this.chatSection.indexOfChatBord(channelUrl); + this.popup.showInvitePopup(this.chatSection.self, index); + this.spinner.insert(this.popup.invitePopup.list); + let channelSet = this.getChannelSet(channelUrl); + const channel = channelSet.channel; + _getUserList(channel); + + this.popup.addClickEvent( + this.popup.invitePopup.inviteBtn, + () => { + if ( + !hasClass(this.popup.invitePopup.inviteBtn, className.DISABLED) + ) { + addClass(this.popup.invitePopup.inviteBtn, className.DISABLED); + this.spinner.insert(this.popup.invitePopup.inviteBtn); + let selectedUserIds = this.popup.getSelectedUserIds( + this.popup.invitePopup.list + ); + let channelSet = this.getChannelSet(channelUrl); + this.sb.inviteMember(channelSet.channel, selectedUserIds, () => { + this.spinner.remove(this.popup.invitePopup.inviteBtn); + this.closeInvitePopup(); + this.listBoard.setChannelTitle( + channelSet.channel.url, + this.sb.getNicknamesString(channelSet.channel) + ); + this.updateChannelInfo(chatBoard, channelSet.channel); + }); + } + }, + { invite: true } + ); + + this.popup.addScrollEvent(() => { + _getUserList(channel, true); + }); + } + }); + this.spinner.insert(chatBoard.content); + this.sb.getChannelInfo(channelUrl, channel => { + this.updateChannelInfo(chatBoard, channel); + let channelSet = this.getChannelSet(channel); + this.getMessageList(channelSet, chatBoard, false, () => { + this.chatScrollEvent(chatBoard, channelSet); + }); + channel.markAsRead(); + this.updateUnreadMessageCount(channel); + + let listItem = this.listBoard.getChannelItem(channelUrl); + if (!listItem) { + listItem = this.createChannelItem(channel); + this.listBoard.list.insertBefore( + listItem, + this.listBoard.list.firstChild + ); + } + }); + } + + updateChannelInfo(target, channel) { + this.chatSection.updateChatTop( + target, + this.sb.getMemberCount(channel), + this.sb.getNicknamesString(channel) + ); + } + + updateUnreadMessageCount(channel) { + this.sb.getTotalUnreadCount(unreadCount => { + this.widgetBtn.setUnreadCount(unreadCount); + }); + + if (channel) { + this.listBoard.setChannelUnread(channel.url, channel.unreadMessageCount); + } + } + + getMessageList(channelSet, target, loadmore, scrollEvent) { + this.sb.getMessageList(channelSet, messageList => { + let messageItems = messageList.slice(); + let tempTime; + for (var index = 0; index < messageList.length; index++) { + let message = messageList[index]; + loadmore + ? channelSet.message.unshift(message) + : channelSet.message.push(message); + + let time = this.sb.getMessageTime(message); + if (time.indexOf(":") > -1) { + time = TIME_STRING_TODAY; + } + if (tempTime != time) { + tempTime = time; + insertMessageInList( + messageItems, + messageItems.indexOf(message), + new this.timeMessage(time) + ); + } + } + + let scrollToBottom = false; + if (!loadmore) { + if (tempTime != TIME_STRING_TODAY) { + messageItems.push(new this.timeMessage(TIME_STRING_TODAY)); + } + scrollToBottom = true; + this.spinner.remove(target.content); + this.chatSection.createMessageContent(target); + this.chatSection.addFileSelectEvent(target.file, () => { + let file = target.file.files[0]; + this.sb.sendFileMessage(channelSet.channel, file, message => { + this.messageReceivedAction(channelSet.channel, message); + }); + }); + this.chatSection.addKeyDownEvent(target.input, event => { + if (event.keyCode == KEY_DOWN_KR) { + this.chatSection.textKr = target.input.textContent; + } + + if (event.keyCode == KEY_DOWN_ENTER && !event.shiftKey) { + let textMessage = + target.input.textContent || this.chatSection.textKr; + if (!isEmptyString(textMessage.trim())) { + this.sb.sendTextMessage( + channelSet.channel, + textMessage, + message => { + this.messageReceivedAction(channelSet.channel, message); + } + ); + } + this.chatSection.clearInputText( + target.input, + channelSet.channel.url + ); + this.chatSection.textKr = ""; + channelSet.channel.endTyping(); + } else { + channelSet.channel.startTyping(); + } + this.chatSection.responsiveHeight(channelSet.channel.url); + }); + this.chatSection.addKeyUpEvent(target.input, event => { + let isBottom = this.chatSection.isBottom( + target.messageContent, + target.list + ); + this.chatSection.responsiveHeight(channelSet.channel.url); + if (event.keyCode == KEY_DOWN_ENTER && !event.shiftKey) { + this.chatSection.clearInputText( + target.input, + channelSet.channel.url + ); + if (isBottom) { + this.chatSection.scrollToBottom(target.messageContent); + } + } else { + let textMessage = + target.input.textContent || this.chatSection.textKr; + if (textMessage.length === 0) { + channelSet.channel.endTyping(); + } + } + }); + this.chatSection.addPasteEvent(target.input, event => { + var clipboardData; + var pastedData; + + event.stopPropagation(); + event.preventDefault(); + + clipboardData = event.clipboardData || window.clipboardData; + pastedData = clipboardData.getData("Text"); + + target.input.textContent += pastedData; + }); + } + if (scrollEvent) { + scrollEvent(); + } + this.setMessageItem( + channelSet.channel, + target, + messageItems, + loadmore, + scrollToBottom + ); + }); + } + + setMessageItem( + channel, + target, + messageList, + loadmore, + scrollToBottom, + lastMessage + ) { + let firstChild = target.list.firstChild; + let addScrollHeight = 0; + let prevMessage; + let newMessage; + if (lastMessage && messageList[0] && !messageList[0].isTimeMessage) { + prevMessage = lastMessage; + } + for (var i = 0; i < messageList.length; i++) { + let message = messageList[i]; + if (message.isTimeMessage && message.isTimeMessage()) { + newMessage = this.chatSection.createMessageItemTime(message.time); + prevMessage = null; + } else { + let isContinue = false; + if (message.isAdminMessage()) { + newMessage = this.chatSection.createAdminMessageItem(message); + } else { + // isUserMessage() || isFileMessage() + isContinue = + prevMessage && prevMessage.sender + ? message.sender.userId == prevMessage.sender.userId + : false; + let isCurrentUser = this.sb.isCurrentUser(message.sender); + let unreadCount = channel.getReadReceipt(message); + if (message.isUserMessage()) { + newMessage = this.chatSection.createMessageItem( + message, + isCurrentUser, + isContinue, + unreadCount + ); + } else if (message.isFileMessage()) { + newMessage = this.chatSection.createMessageItem( + message, + isCurrentUser, + isContinue, + unreadCount + ); + } + } + prevMessage = message; + } + + if (loadmore) { + target.list.insertBefore(newMessage, firstChild); + addScrollHeight += getFullHeight(newMessage); + } else { + target.list.appendChild(newMessage); + } + } + + if (loadmore) { + target.messageContent.scrollTop = addScrollHeight; + } else if (scrollToBottom) { + this.chatSection.scrollToBottom(target.messageContent); + } + } + + chatScrollEvent(target, channelSet) { + this.chatSection.addScrollEvent(target.messageContent, () => { + if (target.messageContent.scrollTop == 0) { + this.getMessageList(channelSet, target, true); + } + }); + } + + getChannelSet(channel, isLast) { + let isObject = true; + if (typeof channel === TYPE_STRING || channel instanceof String) { + isObject = false; + } + + let channelSet = this.activeChannelSetList.filter(obj => { + return isObject ? obj.channel == channel : obj.channel.url == channel; + })[0]; + + if (!channelSet && isObject) { + channelSet = { + channel: channel, + query: channel.createPreviousMessageListQuery(), + message: [] + }; + isLast + ? this.activeChannelSetList.push(channelSet) + : this.activeChannelSetList.unshift(channelSet); + } + + return channelSet; + } + + removeChannelSet(channel) { + let isObject = true; + if (typeof channel === TYPE_STRING || channel instanceof String) { + isObject = false; + } + + this.activeChannelSetList = this.activeChannelSetList.filter(function (obj) { + return isObject ? obj.channel != channel : obj.channel.url != channel; + }); + } + + toggleBoard(isShow) { + if (isShow) { + hide( + addClass( + removeClass(this.widgetBtn.self, className.FADE_IN), + className.FADE_OUT + ) + ); + show( + addClass( + removeClass(this.listBoard.self, className.FADE_OUT), + className.FADE_IN + ) + ); + } else { + hide( + addClass( + removeClass(this.listBoard.self, className.FADE_IN), + className.FADE_OUT + ) + ); + show( + addClass( + removeClass(this.widgetBtn.self, className.FADE_OUT), + className.FADE_IN + ) + ); + } + } +} + +window.sbWidget = new SBWidget(); diff --git a/web-widget/src/scss/_animation.scss b/javascript/javascript-widget/src/scss/_animation.scss similarity index 100% rename from web-widget/src/scss/_animation.scss rename to javascript/javascript-widget/src/scss/_animation.scss diff --git a/web-widget/src/scss/_icons.scss b/javascript/javascript-widget/src/scss/_icons.scss similarity index 100% rename from web-widget/src/scss/_icons.scss rename to javascript/javascript-widget/src/scss/_icons.scss diff --git a/web-widget/src/scss/_mixins.scss b/javascript/javascript-widget/src/scss/_mixins.scss similarity index 100% rename from web-widget/src/scss/_mixins.scss rename to javascript/javascript-widget/src/scss/_mixins.scss diff --git a/web-widget/src/scss/_variables.scss b/javascript/javascript-widget/src/scss/_variables.scss similarity index 100% rename from web-widget/src/scss/_variables.scss rename to javascript/javascript-widget/src/scss/_variables.scss diff --git a/javascript/javascript-widget/src/scss/mixins/_border-radius.scss b/javascript/javascript-widget/src/scss/mixins/_border-radius.scss new file mode 100644 index 00000000..95bb40a1 --- /dev/null +++ b/javascript/javascript-widget/src/scss/mixins/_border-radius.scss @@ -0,0 +1,59 @@ +@mixin border-radius($radius) { + border-radius: $radius; + -webkit-border-radius: $radius; + -moz-border-radius: $radius; + -ms-border-radius: $radius; + -o-border-radius: $radius; +} + +@mixin border-top-radius($radius) { + border-top-right-radius: $radius; + border-top-left-radius: $radius; + -webkit-border-top-right-radius: $radius; + -webkit-border-top-left-radius: $radius; + -moz-border-top-right-radius: $radius; + -moz-border-top-left-radius: $radius; + -ms-border-top-right-radius: $radius; + -ms-border-top-left-radius: $radius; + -o-border-top-right-radius: $radius; + -o-border-top-left-radius: $radius; +} + +@mixin border-right-radius($radius) { + border-bottom-right-radius: $radius; + border-top-right-radius: $radius; + -webkit-border-bottom-right-radius: $radius; + -webkit-border-top-right-radius: $radius; + -moz-border-bottom-right-radius: $radius; + -moz-border-top-right-radius: $radius; + -ms-border-bottom-right-radius: $radius; + -ms-border-top-right-radius: $radius; + -o-border-bottom-right-radius: $radius; + -o-border-top-right-radius: $radius; +} + +@mixin border-bottom-radius($radius) { + border-bottom-right-radius: $radius; + border-bottom-left-radius: $radius; + -webkit-border-bottom-right-radius: $radius; + -webkit-border-bottom-left-radius: $radius; + -moz-border-bottom-right-radius: $radius; + -moz-border-bottom-left-radius: $radius; + -ms-border-bottom-right-radius: $radius; + -ms-border-bottom-left-radius: $radius; + -o-border-bottom-right-radius: $radius; + -o-border-bottom-left-radius: $radius; +} + +@mixin border-left-radius($radius) { + border-bottom-left-radius: $radius; + border-top-left-radius: $radius; + -webkit-border-bottom-left-radius: $radius; + -webkit-border-top-left-radius: $radius; + -moz-border-bottom-left-radius: $radius; + -moz-border-top-left-radius: $radius; + -ms-border-bottom-left-radius: $radius; + -ms-border-top-left-radius: $radius; + -o-border-bottom-left-radius: $radius; + -o-border-top-left-radius: $radius; +} diff --git a/web-widget/src/scss/mixins/_box-shadow.scss b/javascript/javascript-widget/src/scss/mixins/_box-shadow.scss similarity index 100% rename from web-widget/src/scss/mixins/_box-shadow.scss rename to javascript/javascript-widget/src/scss/mixins/_box-shadow.scss diff --git a/javascript/javascript-widget/src/scss/mixins/_reset.scss b/javascript/javascript-widget/src/scss/mixins/_reset.scss new file mode 100644 index 00000000..eac43c4c --- /dev/null +++ b/javascript/javascript-widget/src/scss/mixins/_reset.scss @@ -0,0 +1,9 @@ +@mixin reset { + margin: 0; + padding: 0; + font-size: 100%; + line-height: 1; + width: auto; + height: auto; + box-sizing: initial; +} diff --git a/web-live-chat/src/scss/mixins/_state.scss b/javascript/javascript-widget/src/scss/mixins/_state.scss similarity index 100% rename from web-live-chat/src/scss/mixins/_state.scss rename to javascript/javascript-widget/src/scss/mixins/_state.scss diff --git a/javascript/javascript-widget/src/scss/mixins/_transform.scss b/javascript/javascript-widget/src/scss/mixins/_transform.scss new file mode 100644 index 00000000..026f6d1f --- /dev/null +++ b/javascript/javascript-widget/src/scss/mixins/_transform.scss @@ -0,0 +1,7 @@ +@mixin transform-translate($x, $y) { + -webkit-transform: translate($x, $y); + -moz-transform: translate($x, $y); + -ms-transform: translate($x, $y); + -o-transform: translate($x, $y); + transform: translate($x, $y); +} diff --git a/web-widget/src/scss/widget.scss b/javascript/javascript-widget/src/scss/widget.scss similarity index 97% rename from web-widget/src/scss/widget.scss rename to javascript/javascript-widget/src/scss/widget.scss index eabd382b..dd4223d4 100644 --- a/web-widget/src/scss/widget.scss +++ b/javascript/javascript-widget/src/scss/widget.scss @@ -716,7 +716,7 @@ .user-content { @include reset(); width: 100%; - height: calc(100% - 64px); + height: calc(100% - 52px); background-color: $color-white; overflow-y: scroll; overflow-x: hidden; @@ -873,6 +873,7 @@ .text { @include reset(); + display: inline-block; width: calc(100% - 8px); min-height: 24px; max-height: 90px; @@ -964,6 +965,34 @@ padding: 6px; word-wrap: break-word; @include border-radius(5px); + + .preview-name { + font-size: 11px; + font-weight: 300; + } + .preview-title { + margin-top: 4px; + font-size: 13px; + font-weight: 500; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + width: 180px; + height: 13px; + } + .preview-description { + margin-top: 4px; + font-size: 11px; + font-weight: 300; + } + .preview-iamge { + width: 180px !important; + height: 90px !important; + background-size: 180px 180px; + background-position-x: center; + background-position-y: 30%; + margin-top: 4px; + } } .file-message { @include reset(); diff --git a/javascript/javascript-widget/webpack.config.js b/javascript/javascript-widget/webpack.config.js new file mode 100644 index 00000000..46aaad16 --- /dev/null +++ b/javascript/javascript-widget/webpack.config.js @@ -0,0 +1,54 @@ +var path = require('path'); + +module.exports = { + entry: { + widget: ['babel-polyfill', './src/js/widget.js'] + }, + output: { + path: path.resolve(__dirname + '/dist'), + filename: '[name].SendBird.js', + publicPath: "dist" + }, + devtool: "cheap-eval-source-map", + devServer: { + publicPath: '/dist/', + compress: true, + port: 9000 + }, + module: { + rules: [ + { // SCSS + test: /\.scss$/, + use: [ + { + loader: 'style-loader' + }, + { + loader: 'css-loader' + }, + { + loader: 'sass-loader' + } + ] + }, + { // ESLint + enforce: 'pre', + test: /\.js$/, + exclude: /(node_modules|SendBird.min.js)/, + use: [ + { + loader: 'eslint-loader', + options: { + failOnError: true + } + } + ] + }, + { // ES6 + test: /\.js$/, + exclude: /(node_modules)/, + loader: 'babel-loader' + } + ] + } +}; diff --git a/react-native-sample/SendBirdReactNativeSample/.babelrc b/react-native-sample/SendBirdReactNativeSample/.babelrc deleted file mode 100644 index 8df53fe4..00000000 --- a/react-native-sample/SendBirdReactNativeSample/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ -"presets": ["react-native"] -} \ No newline at end of file diff --git a/react-native-sample/SendBirdReactNativeSample/.flowconfig b/react-native-sample/SendBirdReactNativeSample/.flowconfig deleted file mode 100644 index b38ea97e..00000000 --- a/react-native-sample/SendBirdReactNativeSample/.flowconfig +++ /dev/null @@ -1,44 +0,0 @@ -[ignore] -; We fork some components by platform -.*/*[.]android.js - -; Ignore "BUCK" generated dirs -/\.buckd/ - -; Ignore unexpected extra "@providesModule" -.*/node_modules/.*/node_modules/fbjs/.* - -; Ignore duplicate module providers -; For RN Apps installed via npm, "Libraries" folder is inside -; "node_modules/react-native" but in the source repo it is in the root -.*/Libraries/react-native/React.js -.*/Libraries/react-native/ReactNative.js - -[include] - -[libs] -node_modules/react-native/Libraries/react-native/react-native-interface.js -node_modules/react-native/flow -flow/ - -[options] -module.system=haste - -experimental.strict_type_args=true - -munge_underscores=true - -module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' - -suppress_type=$FlowIssue -suppress_type=$FlowFixMe -suppress_type=$FixMe - -suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-7]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) -suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-7]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ -suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy - -unsafe.enable_getters_and_setters=true - -[version] -^0.37.0 diff --git a/react-native-sample/SendBirdReactNativeSample/.gitignore b/react-native-sample/SendBirdReactNativeSample/.gitignore deleted file mode 100644 index 8fce6397..00000000 --- a/react-native-sample/SendBirdReactNativeSample/.gitignore +++ /dev/null @@ -1,54 +0,0 @@ -# OSX -# -.DS_Store - -# Xcode -# -build/ -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 -xcuserdata -*.xccheckout -*.moved-aside -DerivedData -*.hmap -*.ipa -*.xcuserstate -project.xcworkspace - -# Android/IntelliJ -# -build/ -.idea -.gradle -local.properties -*.iml - -# node.js -# -node_modules/ -npm-debug.log -yarn-error.log - -# BUCK -buck-out/ -\.buckd/ -android/app/libs -*.keystore - -# fastlane -# -# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the -# screenshots whenever they are needed. -# For more information about the recommended setup visit: -# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md - -fastlane/report.xml -fastlane/Preview.html -fastlane/screenshots diff --git a/react-native-sample/SendBirdReactNativeSample/android/app/BUCK b/react-native-sample/SendBirdReactNativeSample/android/app/BUCK deleted file mode 100644 index 2d7ee641..00000000 --- a/react-native-sample/SendBirdReactNativeSample/android/app/BUCK +++ /dev/null @@ -1,66 +0,0 @@ -import re - -# To learn about Buck see [Docs](https://buckbuild.com/). -# To run your application with Buck: -# - install Buck -# - `npm start` - to start the packager -# - `cd android` -# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` -# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck -# - `buck install -r android/app` - compile, install and run application -# - -lib_deps = [] -for jarfile in glob(['libs/*.jar']): - name = 'jars__' + re.sub(r'^.*/([^/]+)\.jar$', r'\1', jarfile) - lib_deps.append(':' + name) - prebuilt_jar( - name = name, - binary_jar = jarfile, - ) - -for aarfile in glob(['libs/*.aar']): - name = 'aars__' + re.sub(r'^.*/([^/]+)\.aar$', r'\1', aarfile) - lib_deps.append(':' + name) - android_prebuilt_aar( - name = name, - aar = aarfile, - ) - -android_library( - name = 'all-libs', - exported_deps = lib_deps -) - -android_library( - name = 'app-code', - srcs = glob([ - 'src/main/java/**/*.java', - ]), - deps = [ - ':all-libs', - ':build_config', - ':res', - ], -) - -android_build_config( - name = 'build_config', - package = 'com.sendbirdreactnativesample', -) - -android_resource( - name = 'res', - res = 'src/main/res', - package = 'com.sendbirdreactnativesample', -) - -android_binary( - name = 'app', - package_type = 'debug', - manifest = 'src/main/AndroidManifest.xml', - keystore = '//android/keystores:debug', - deps = [ - ':app-code', - ], -) diff --git a/react-native-sample/SendBirdReactNativeSample/android/app/build.gradle b/react-native-sample/SendBirdReactNativeSample/android/app/build.gradle deleted file mode 100644 index 903eda02..00000000 --- a/react-native-sample/SendBirdReactNativeSample/android/app/build.gradle +++ /dev/null @@ -1,142 +0,0 @@ -apply plugin: "com.android.application" - -import com.android.build.OutputFile - -/** - * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets - * and bundleReleaseJsAndAssets). - * These basically call `react-native bundle` with the correct arguments during the Android build - * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the - * bundle directly from the development server. Below you can see all the possible configurations - * and their defaults. If you decide to add a configuration block, make sure to add it before the - * `apply from: "../../node_modules/react-native/react.gradle"` line. - * - * project.ext.react = [ - * // the name of the generated asset file containing your JS bundle - * bundleAssetName: "index.android.bundle", - * - * // the entry file for bundle generation - * entryFile: "index.android.js", - * - * // whether to bundle JS and assets in debug mode - * bundleInDebug: false, - * - * // whether to bundle JS and assets in release mode - * bundleInRelease: true, - * - * // whether to bundle JS and assets in another build variant (if configured). - * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants - * // The configuration property can be in the following formats - * // 'bundleIn${productFlavor}${buildType}' - * // 'bundleIn${buildType}' - * // bundleInFreeDebug: true, - * // bundleInPaidRelease: true, - * // bundleInBeta: true, - * - * // the root of your project, i.e. where "package.json" lives - * root: "../../", - * - * // where to put the JS bundle asset in debug mode - * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", - * - * // where to put the JS bundle asset in release mode - * jsBundleDirRelease: "$buildDir/intermediates/assets/release", - * - * // where to put drawable resources / React Native assets, e.g. the ones you use via - * // require('./image.png')), in debug mode - * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", - * - * // where to put drawable resources / React Native assets, e.g. the ones you use via - * // require('./image.png')), in release mode - * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", - * - * // by default the gradle tasks are skipped if none of the JS files or assets change; this means - * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to - * // date; if you have any other folders that you want to ignore for performance reasons (gradle - * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ - * // for example, you might want to remove it from here. - * inputExcludes: ["android/**", "ios/**"], - * - * // override which node gets called and with what additional arguments - * nodeExecutableAndArgs: ["node"] - * - * // supply additional arguments to the packager - * extraPackagerArgs: [] - * ] - */ - -apply from: "../../node_modules/react-native/react.gradle" - -/** - * Set this to true to create two separate APKs instead of one: - * - An APK that only works on ARM devices - * - An APK that only works on x86 devices - * The advantage is the size of the APK is reduced by about 4MB. - * Upload all the APKs to the Play Store and people will download - * the correct one based on the CPU architecture of their device. - */ -def enableSeparateBuildPerCPUArchitecture = false - -/** - * Run Proguard to shrink the Java bytecode in release builds. - */ -def enableProguardInReleaseBuilds = false - -android { - compileSdkVersion 23 - buildToolsVersion "23.0.1" - - defaultConfig { - applicationId "com.sendbirdreactnativesample" - minSdkVersion 16 - targetSdkVersion 22 - versionCode 1 - versionName "1.0" - ndk { - abiFilters "armeabi-v7a", "x86" - } - } - splits { - abi { - reset() - enable enableSeparateBuildPerCPUArchitecture - universalApk false // If true, also generate a universal APK - include "armeabi-v7a", "x86" - } - } - buildTypes { - release { - minifyEnabled enableProguardInReleaseBuilds - proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" - } - } - // applicationVariants are e.g. debug, release - applicationVariants.all { variant -> - variant.outputs.each { output -> - // For each separate APK per architecture, set a unique version code as described here: - // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits - def versionCodes = ["armeabi-v7a":1, "x86":2] - def abi = output.getFilter(OutputFile.ABI) - if (abi != null) { // null for the universal-debug, universal-release variants - output.versionCodeOverride = - versionCodes.get(abi) * 1048576 + defaultConfig.versionCode - } - } - } -} - -dependencies { - compile project(':react-native-fs') - compile project(':react-native-image-picker') - compile project(':react-native-push-notification') - compile fileTree(dir: "libs", include: ["*.jar"]) - compile "com.android.support:appcompat-v7:23.0.1" - compile "com.facebook.react:react-native:+" // From node_modules -} - -// Run this once to be able to run the application with BUCK -// puts all compile dependencies into folder libs for BUCK to use -task copyDownloadableDepsToLibs(type: Copy) { - from configurations.compile - into 'libs' -} diff --git a/react-native-sample/SendBirdReactNativeSample/android/app/proguard-rules.pro b/react-native-sample/SendBirdReactNativeSample/android/app/proguard-rules.pro deleted file mode 100644 index 48361a90..00000000 --- a/react-native-sample/SendBirdReactNativeSample/android/app/proguard-rules.pro +++ /dev/null @@ -1,66 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Disabling obfuscation is useful if you collect stack traces from production crashes -# (unless you are using a system that supports de-obfuscate the stack traces). --dontobfuscate - -# React Native - -# Keep our interfaces so they can be used by other ProGuard rules. -# See http://sourceforge.net/p/proguard/bugs/466/ --keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip --keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters --keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip - -# Do not strip any method/class that is annotated with @DoNotStrip --keep @com.facebook.proguard.annotations.DoNotStrip class * --keep @com.facebook.common.internal.DoNotStrip class * --keepclassmembers class * { - @com.facebook.proguard.annotations.DoNotStrip *; - @com.facebook.common.internal.DoNotStrip *; -} - --keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { - void set*(***); - *** get*(); -} - --keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } --keep class * extends com.facebook.react.bridge.NativeModule { *; } --keepclassmembers,includedescriptorclasses class * { native ; } --keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } --keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } --keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } - --dontwarn com.facebook.react.** - -# okhttp - --keepattributes Signature --keepattributes *Annotation* --keep class okhttp3.** { *; } --keep interface okhttp3.** { *; } --dontwarn okhttp3.** - -# okio - --keep class sun.misc.Unsafe { *; } --dontwarn java.nio.file.* --dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement --dontwarn okio.** diff --git a/react-native-sample/SendBirdReactNativeSample/android/app/src/main/AndroidManifest.xml b/react-native-sample/SendBirdReactNativeSample/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 016631cb..00000000 --- a/react-native-sample/SendBirdReactNativeSample/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/react-native-sample/SendBirdReactNativeSample/android/app/src/main/java/com/sendbirdreactnativesample/MainActivity.java b/react-native-sample/SendBirdReactNativeSample/android/app/src/main/java/com/sendbirdreactnativesample/MainActivity.java deleted file mode 100644 index dd1ba2c0..00000000 --- a/react-native-sample/SendBirdReactNativeSample/android/app/src/main/java/com/sendbirdreactnativesample/MainActivity.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.sendbirdreactnativesample; - -import com.facebook.react.ReactActivity; - -public class MainActivity extends ReactActivity { - - /** - * Returns the name of the main component registered from JavaScript. - * This is used to schedule rendering of the component. - */ - @Override - protected String getMainComponentName() { - return "SendBirdReactNativeSample"; - } -} diff --git a/react-native-sample/SendBirdReactNativeSample/android/app/src/main/java/com/sendbirdreactnativesample/MainApplication.java b/react-native-sample/SendBirdReactNativeSample/android/app/src/main/java/com/sendbirdreactnativesample/MainApplication.java deleted file mode 100644 index f82d6a89..00000000 --- a/react-native-sample/SendBirdReactNativeSample/android/app/src/main/java/com/sendbirdreactnativesample/MainApplication.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.sendbirdreactnativesample; - -import android.app.Application; -import android.util.Log; - -import com.facebook.react.ReactApplication; -import com.rnfs.RNFSPackage; -import com.imagepicker.ImagePickerPackage; -import com.dieam.reactnativepushnotification.ReactNativePushNotificationPackage; -import com.facebook.react.ReactInstanceManager; -import com.facebook.react.ReactNativeHost; -import com.facebook.react.ReactPackage; -import com.facebook.react.shell.MainReactPackage; -import com.facebook.soloader.SoLoader; - -import java.util.Arrays; -import java.util.List; - -public class MainApplication extends Application implements ReactApplication { - - private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { - @Override - public boolean getUseDeveloperSupport() { - return BuildConfig.DEBUG; - } - - @Override - protected List getPackages() { - return Arrays.asList( - new MainReactPackage(), - new RNFSPackage(), - new ImagePickerPackage(), - new ReactNativePushNotificationPackage() - ); - } - }; - - @Override - public ReactNativeHost getReactNativeHost() { - return mReactNativeHost; - } - - @Override - public void onCreate() { - super.onCreate(); - SoLoader.init(this, /* native exopackage */ false); - } -} diff --git a/react-native-sample/SendBirdReactNativeSample/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/react-native-sample/SendBirdReactNativeSample/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index cde69bcc..00000000 Binary files a/react-native-sample/SendBirdReactNativeSample/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/react-native-sample/SendBirdReactNativeSample/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/react-native-sample/SendBirdReactNativeSample/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index c133a0cb..00000000 Binary files a/react-native-sample/SendBirdReactNativeSample/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/react-native-sample/SendBirdReactNativeSample/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/react-native-sample/SendBirdReactNativeSample/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index bfa42f0e..00000000 Binary files a/react-native-sample/SendBirdReactNativeSample/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/react-native-sample/SendBirdReactNativeSample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/react-native-sample/SendBirdReactNativeSample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 324e72cd..00000000 Binary files a/react-native-sample/SendBirdReactNativeSample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/react-native-sample/SendBirdReactNativeSample/android/app/src/main/res/values/strings.xml b/react-native-sample/SendBirdReactNativeSample/android/app/src/main/res/values/strings.xml deleted file mode 100644 index 4c186dbe..00000000 --- a/react-native-sample/SendBirdReactNativeSample/android/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - SendBirdReactNativeSample - diff --git a/react-native-sample/SendBirdReactNativeSample/android/build.gradle b/react-native-sample/SendBirdReactNativeSample/android/build.gradle deleted file mode 100644 index fcba4c58..00000000 --- a/react-native-sample/SendBirdReactNativeSample/android/build.gradle +++ /dev/null @@ -1,24 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - -buildscript { - repositories { - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:1.3.1' - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } -} - -allprojects { - repositories { - mavenLocal() - jcenter() - maven { - // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm - url "$rootDir/../node_modules/react-native/android" - } - } -} diff --git a/react-native-sample/SendBirdReactNativeSample/android/google-services.json b/react-native-sample/SendBirdReactNativeSample/android/google-services.json deleted file mode 100644 index a350e217..00000000 --- a/react-native-sample/SendBirdReactNativeSample/android/google-services.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "project_info": { - "project_number": "984140644677", - "firebase_url": "https://sendbird-sample.firebaseio.com", - "project_id": "sendbird-sample", - "storage_bucket": "sendbird-sample.appspot.com" - }, - "client": [ - { - "client_info": { - "mobilesdk_app_id": "1:984140644677:android:abe06d49c04fba23", - "android_client_info": { - "package_name": "com.sendbird.android.sample" - } - }, - "oauth_client": [ - { - "client_id": "984140644677-75b8ti7rnl9ojhu930phht25emuifkki.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "984140644677-ajrt7j1g982mntarduj22mlq1dberha0.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyDxYBEWhz5XUP8twJaGDE249SlEQUfalIc" - } - ], - "services": { - "analytics_service": { - "status": 1 - }, - "appinvite_service": { - "status": 1, - "other_platform_oauth_client": [] - }, - "ads_service": { - "status": 2 - } - } - } - ], - "configuration_version": "1" -} \ No newline at end of file diff --git a/react-native-sample/SendBirdReactNativeSample/android/gradle.properties b/react-native-sample/SendBirdReactNativeSample/android/gradle.properties deleted file mode 100644 index 1fd964e9..00000000 --- a/react-native-sample/SendBirdReactNativeSample/android/gradle.properties +++ /dev/null @@ -1,20 +0,0 @@ -# Project-wide Gradle settings. - -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. - -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html - -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -# Default value: -Xmx10248m -XX:MaxPermSize=256m -# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 - -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true - -android.useDeprecatedNdk=true diff --git a/react-native-sample/SendBirdReactNativeSample/android/gradle/wrapper/gradle-wrapper.jar b/react-native-sample/SendBirdReactNativeSample/android/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index b5166dad..00000000 Binary files a/react-native-sample/SendBirdReactNativeSample/android/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/react-native-sample/SendBirdReactNativeSample/android/gradle/wrapper/gradle-wrapper.properties b/react-native-sample/SendBirdReactNativeSample/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index b9fbfaba..00000000 --- a/react-native-sample/SendBirdReactNativeSample/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip diff --git a/react-native-sample/SendBirdReactNativeSample/android/gradlew b/react-native-sample/SendBirdReactNativeSample/android/gradlew deleted file mode 100755 index 91a7e269..00000000 --- a/react-native-sample/SendBirdReactNativeSample/android/gradlew +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env bash - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; -esac - -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/react-native-sample/SendBirdReactNativeSample/android/gradlew.bat b/react-native-sample/SendBirdReactNativeSample/android/gradlew.bat deleted file mode 100644 index aec99730..00000000 --- a/react-native-sample/SendBirdReactNativeSample/android/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/react-native-sample/SendBirdReactNativeSample/android/keystores/BUCK b/react-native-sample/SendBirdReactNativeSample/android/keystores/BUCK deleted file mode 100644 index 15da20e6..00000000 --- a/react-native-sample/SendBirdReactNativeSample/android/keystores/BUCK +++ /dev/null @@ -1,8 +0,0 @@ -keystore( - name = 'debug', - store = 'debug.keystore', - properties = 'debug.keystore.properties', - visibility = [ - 'PUBLIC', - ], -) diff --git a/react-native-sample/SendBirdReactNativeSample/android/settings.gradle b/react-native-sample/SendBirdReactNativeSample/android/settings.gradle deleted file mode 100644 index 847df8a3..00000000 --- a/react-native-sample/SendBirdReactNativeSample/android/settings.gradle +++ /dev/null @@ -1,9 +0,0 @@ -rootProject.name = 'SendBirdReactNativeSample' -include ':react-native-fs' -project(':react-native-fs').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fs/android') -include ':react-native-image-picker' -project(':react-native-image-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-image-picker/android') -include ':react-native-push-notification' -project(':react-native-push-notification').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-push-notification/android') - -include ':app' diff --git a/react-native-sample/SendBirdReactNativeSample/app.json b/react-native-sample/SendBirdReactNativeSample/app.json deleted file mode 100644 index 3e92e794..00000000 --- a/react-native-sample/SendBirdReactNativeSample/app.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "SendBirdReactNativeSample", - "displayName": "SendBirdReactNativeSample" -} \ No newline at end of file diff --git a/react-native-sample/SendBirdReactNativeSample/index.android.js b/react-native-sample/SendBirdReactNativeSample/index.android.js deleted file mode 100644 index e46b2531..00000000 --- a/react-native-sample/SendBirdReactNativeSample/index.android.js +++ /dev/null @@ -1,8 +0,0 @@ -import React from 'react'; -import { - AppRegistry -} from 'react-native'; - -import Main from './src/main'; - -AppRegistry.registerComponent('SendBirdReactNativeSample', () => Main); diff --git a/react-native-sample/SendBirdReactNativeSample/index.ios.js b/react-native-sample/SendBirdReactNativeSample/index.ios.js deleted file mode 100644 index e46b2531..00000000 --- a/react-native-sample/SendBirdReactNativeSample/index.ios.js +++ /dev/null @@ -1,8 +0,0 @@ -import React from 'react'; -import { - AppRegistry -} from 'react-native'; - -import Main from './src/main'; - -AppRegistry.registerComponent('SendBirdReactNativeSample', () => Main); diff --git a/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample.xcodeproj/project.pbxproj b/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample.xcodeproj/project.pbxproj deleted file mode 100644 index 29236b45..00000000 --- a/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample.xcodeproj/project.pbxproj +++ /dev/null @@ -1,1406 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; }; - 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; }; - 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; }; - 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; }; - 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; }; - 00E356F31AD99517003FC87E /* SendBirdReactNativeSampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* SendBirdReactNativeSampleTests.m */; }; - 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; }; - 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; }; - 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; }; - 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; - 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; }; - 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; - 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; - 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; - 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; - 2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; - 2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; - 2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; - 2D02E4C21E0B4AEC006451C7 /* libRCTAnimation-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation-tvOS.a */; }; - 2D02E4C31E0B4AEC006451C7 /* libRCTImage-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */; }; - 2D02E4C41E0B4AEC006451C7 /* libRCTLinking-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */; }; - 2D02E4C51E0B4AEC006451C7 /* libRCTNetwork-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */; }; - 2D02E4C61E0B4AEC006451C7 /* libRCTSettings-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */; }; - 2D02E4C71E0B4AEC006451C7 /* libRCTText-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */; }; - 2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */; }; - 2D02E4C91E0B4AEC006451C7 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3EA31DF850E9000B6D8A /* libReact.a */; }; - 2DCD954D1E0B4F2C00145EB5 /* SendBirdReactNativeSampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* SendBirdReactNativeSampleTests.m */; }; - 2F66A0311E58ED8D00D55F29 /* libRCTPushNotification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F66A01F1E58ED7000D55F29 /* libRCTPushNotification.a */; }; - 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; }; - 66992F0862F14B45B01E90B5 /* libRNImagePicker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 86AA0C358A8D40C8901C3F34 /* libRNImagePicker.a */; }; - 7892B94A76834F778B032D17 /* libRNFS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C265F14C574DCA8B3D90A7 /* libRNFS.a */; }; - 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTActionSheet; - }; - 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTGeolocation; - }; - 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 58B5115D1A9E6B3D00147676; - remoteInfo = RCTImage; - }; - 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 58B511DB1A9E6C8500147676; - remoteInfo = RCTNetwork; - }; - 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 832C81801AAF6DEF007FA2F7; - remoteInfo = RCTVibration; - }; - 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 13B07F861A680F5B00A75B9A; - remoteInfo = SendBirdReactNativeSample; - }; - 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTSettings; - }; - 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3C86DF461ADF2C930047B81A; - remoteInfo = RCTWebSocket; - }; - 146834031AC3E56700842450 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192; - remoteInfo = React; - }; - 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 2D02E47A1E0B4A5D006451C7; - remoteInfo = "SendBirdReactNativeSample-tvOS"; - }; - 2F66A01E1E58ED7000D55F29 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 2F66A00F1E58ED7000D55F29 /* RCTPushNotification.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTPushNotification; - }; - 2F66A0201E58ED7000D55F29 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 2F66A00F1E58ED7000D55F29 /* RCTPushNotification.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D05745F1DE6004600184BB4; - remoteInfo = "RCTPushNotification-tvOS"; - }; - 2F66A05D1E58F9FF00D55F29 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = DAA1237B9B154DEDB991C6D1 /* RNImagePicker.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 014A3B5C1C6CF33500B6D375; - remoteInfo = RNImagePicker; - }; - 2F66A08A1E599CE900D55F29 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = B79A3B3E02DC42649F3D3DAA /* RNFS.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = F12AFB9B1ADAF8F800E0535D; - remoteInfo = RNFS; - }; - 3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A283A1D9B042B00D4039D; - remoteInfo = "RCTImage-tvOS"; - }; - 3DAD3E871DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28471D9B043800D4039D; - remoteInfo = "RCTLinking-tvOS"; - }; - 3DAD3E8B1DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28541D9B044C00D4039D; - remoteInfo = "RCTNetwork-tvOS"; - }; - 3DAD3E8F1DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28611D9B046600D4039D; - remoteInfo = "RCTSettings-tvOS"; - }; - 3DAD3E931DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A287B1D9B048500D4039D; - remoteInfo = "RCTText-tvOS"; - }; - 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28881D9B049200D4039D; - remoteInfo = "RCTWebSocket-tvOS"; - }; - 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28131D9B038B00D4039D; - remoteInfo = "React-tvOS"; - }; - 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3C059A1DE3340900C268FA; - remoteInfo = yoga; - }; - 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3C06751DE3340C00C268FA; - remoteInfo = "yoga-tvOS"; - }; - 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD9251DE5FBEC00167DC4; - remoteInfo = cxxreact; - }; - 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD9321DE5FBEE00167DC4; - remoteInfo = "cxxreact-tvOS"; - }; - 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD90B1DE5FBD600167DC4; - remoteInfo = jschelpers; - }; - 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD9181DE5FBD800167DC4; - remoteInfo = "jschelpers-tvOS"; - }; - 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTAnimation; - }; - 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28201D9B03D100D4039D; - remoteInfo = "RCTAnimation-tvOS"; - }; - 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTLinking; - }; - 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 58B5119B1A9E6C1200147676; - remoteInfo = RCTText; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; }; - 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = ""; }; - 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = "../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj"; sourceTree = ""; }; - 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = ""; }; - 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = ""; }; - 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = ""; }; - 00E356EE1AD99517003FC87E /* SendBirdReactNativeSampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SendBirdReactNativeSampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 00E356F21AD99517003FC87E /* SendBirdReactNativeSampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SendBirdReactNativeSampleTests.m; sourceTree = ""; }; - 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = ""; }; - 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = ""; }; - 13B07F961A680F5B00A75B9A /* SendBirdReactNativeSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SendBirdReactNativeSample.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = SendBirdReactNativeSample/AppDelegate.h; sourceTree = ""; }; - 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = SendBirdReactNativeSample/AppDelegate.m; sourceTree = ""; }; - 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; - 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = SendBirdReactNativeSample/Images.xcassets; sourceTree = ""; }; - 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = SendBirdReactNativeSample/Info.plist; sourceTree = ""; }; - 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = SendBirdReactNativeSample/main.m; sourceTree = ""; }; - 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; }; - 2D02E47B1E0B4A5D006451C7 /* SendBirdReactNativeSample-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "SendBirdReactNativeSample-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 2D02E4901E0B4A5D006451C7 /* SendBirdReactNativeSample-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SendBirdReactNativeSample-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - 2F66A00F1E58ED7000D55F29 /* RCTPushNotification.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTPushNotification.xcodeproj; path = "../node_modules/react-native/Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj"; sourceTree = ""; }; - 2F66A0321E58EDAC00D55F29 /* SendBirdReactNativeSample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = SendBirdReactNativeSample.entitlements; path = SendBirdReactNativeSample/SendBirdReactNativeSample.entitlements; sourceTree = ""; }; - 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = ""; }; - 64C265F14C574DCA8B3D90A7 /* libRNFS.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNFS.a; sourceTree = ""; }; - 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; - 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; }; - 86AA0C358A8D40C8901C3F34 /* libRNImagePicker.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNImagePicker.a; sourceTree = ""; }; - B79A3B3E02DC42649F3D3DAA /* RNFS.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNFS.xcodeproj; path = "../node_modules/react-native-fs/RNFS.xcodeproj"; sourceTree = ""; }; - DAA1237B9B154DEDB991C6D1 /* RNImagePicker.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNImagePicker.xcodeproj; path = "../node_modules/react-native-image-picker/ios/RNImagePicker.xcodeproj"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 00E356EB1AD99517003FC87E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 2F66A0311E58ED8D00D55F29 /* libRCTPushNotification.a in Frameworks */, - 146834051AC3E58100842450 /* libReact.a in Frameworks */, - 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */, - 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */, - 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */, - 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */, - 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */, - 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */, - 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */, - 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */, - 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */, - 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */, - 66992F0862F14B45B01E90B5 /* libRNImagePicker.a in Frameworks */, - 7892B94A76834F778B032D17 /* libRNFS.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 2D02E4781E0B4A5D006451C7 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 2D02E4C91E0B4AEC006451C7 /* libReact.a in Frameworks */, - 2D02E4C21E0B4AEC006451C7 /* libRCTAnimation-tvOS.a in Frameworks */, - 2D02E4C31E0B4AEC006451C7 /* libRCTImage-tvOS.a in Frameworks */, - 2D02E4C41E0B4AEC006451C7 /* libRCTLinking-tvOS.a in Frameworks */, - 2D02E4C51E0B4AEC006451C7 /* libRCTNetwork-tvOS.a in Frameworks */, - 2D02E4C61E0B4AEC006451C7 /* libRCTSettings-tvOS.a in Frameworks */, - 2D02E4C71E0B4AEC006451C7 /* libRCTText-tvOS.a in Frameworks */, - 2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 2D02E48D1E0B4A5D006451C7 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 00C302A81ABCB8CE00DB3ED1 /* Products */ = { - isa = PBXGroup; - children = ( - 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */, - ); - name = Products; - sourceTree = ""; - }; - 00C302B61ABCB90400DB3ED1 /* Products */ = { - isa = PBXGroup; - children = ( - 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */, - ); - name = Products; - sourceTree = ""; - }; - 00C302BC1ABCB91800DB3ED1 /* Products */ = { - isa = PBXGroup; - children = ( - 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */, - 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 00C302D41ABCB9D200DB3ED1 /* Products */ = { - isa = PBXGroup; - children = ( - 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */, - 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 00C302E01ABCB9EE00DB3ED1 /* Products */ = { - isa = PBXGroup; - children = ( - 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */, - ); - name = Products; - sourceTree = ""; - }; - 00E356EF1AD99517003FC87E /* SendBirdReactNativeSampleTests */ = { - isa = PBXGroup; - children = ( - 00E356F21AD99517003FC87E /* SendBirdReactNativeSampleTests.m */, - 00E356F01AD99517003FC87E /* Supporting Files */, - ); - path = SendBirdReactNativeSampleTests; - sourceTree = ""; - }; - 00E356F01AD99517003FC87E /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 00E356F11AD99517003FC87E /* Info.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 139105B71AF99BAD00B5F7CC /* Products */ = { - isa = PBXGroup; - children = ( - 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */, - 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 139FDEE71B06529A00C62182 /* Products */ = { - isa = PBXGroup; - children = ( - 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */, - 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 13B07FAE1A68108700A75B9A /* SendBirdReactNativeSample */ = { - isa = PBXGroup; - children = ( - 2F66A0321E58EDAC00D55F29 /* SendBirdReactNativeSample.entitlements */, - 008F07F21AC5B25A0029DE68 /* main.jsbundle */, - 13B07FAF1A68108700A75B9A /* AppDelegate.h */, - 13B07FB01A68108700A75B9A /* AppDelegate.m */, - 13B07FB51A68108700A75B9A /* Images.xcassets */, - 13B07FB61A68108700A75B9A /* Info.plist */, - 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, - 13B07FB71A68108700A75B9A /* main.m */, - ); - name = SendBirdReactNativeSample; - sourceTree = ""; - }; - 146834001AC3E56700842450 /* Products */ = { - isa = PBXGroup; - children = ( - 146834041AC3E56700842450 /* libReact.a */, - 3DAD3EA31DF850E9000B6D8A /* libReact.a */, - 3DAD3EA51DF850E9000B6D8A /* libyoga.a */, - 3DAD3EA71DF850E9000B6D8A /* libyoga.a */, - 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */, - 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */, - 3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */, - 3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */, - ); - name = Products; - sourceTree = ""; - }; - 2F66A0101E58ED7000D55F29 /* Products */ = { - isa = PBXGroup; - children = ( - 2F66A01F1E58ED7000D55F29 /* libRCTPushNotification.a */, - 2F66A0211E58ED7000D55F29 /* libRCTPushNotification-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 2F66A03F1E58F9FF00D55F29 /* Products */ = { - isa = PBXGroup; - children = ( - 2F66A05E1E58F9FF00D55F29 /* libRNImagePicker.a */, - ); - name = Products; - sourceTree = ""; - }; - 2F66A06C1E599CE900D55F29 /* Products */ = { - isa = PBXGroup; - children = ( - 2F66A08B1E599CE900D55F29 /* libRNFS.a */, - ); - name = Products; - sourceTree = ""; - }; - 5E91572E1DD0AC6500FF2AA8 /* Products */ = { - isa = PBXGroup; - children = ( - 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */, - 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 78C398B11ACF4ADC00677621 /* Products */ = { - isa = PBXGroup; - children = ( - 78C398B91ACF4ADC00677621 /* libRCTLinking.a */, - 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 832341AE1AAA6A7D00B99B32 /* Libraries */ = { - isa = PBXGroup; - children = ( - 2F66A00F1E58ED7000D55F29 /* RCTPushNotification.xcodeproj */, - 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */, - 146833FF1AC3E56700842450 /* React.xcodeproj */, - 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */, - 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */, - 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */, - 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */, - 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */, - 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */, - 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */, - 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */, - 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */, - DAA1237B9B154DEDB991C6D1 /* RNImagePicker.xcodeproj */, - B79A3B3E02DC42649F3D3DAA /* RNFS.xcodeproj */, - ); - name = Libraries; - sourceTree = ""; - }; - 832341B11AAA6A8300B99B32 /* Products */ = { - isa = PBXGroup; - children = ( - 832341B51AAA6A8300B99B32 /* libRCTText.a */, - 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 83CBB9F61A601CBA00E9B192 = { - isa = PBXGroup; - children = ( - 13B07FAE1A68108700A75B9A /* SendBirdReactNativeSample */, - 832341AE1AAA6A7D00B99B32 /* Libraries */, - 00E356EF1AD99517003FC87E /* SendBirdReactNativeSampleTests */, - 83CBBA001A601CBA00E9B192 /* Products */, - ); - indentWidth = 2; - sourceTree = ""; - tabWidth = 2; - }; - 83CBBA001A601CBA00E9B192 /* Products */ = { - isa = PBXGroup; - children = ( - 13B07F961A680F5B00A75B9A /* SendBirdReactNativeSample.app */, - 00E356EE1AD99517003FC87E /* SendBirdReactNativeSampleTests.xctest */, - 2D02E47B1E0B4A5D006451C7 /* SendBirdReactNativeSample-tvOS.app */, - 2D02E4901E0B4A5D006451C7 /* SendBirdReactNativeSample-tvOSTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 00E356ED1AD99517003FC87E /* SendBirdReactNativeSampleTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "SendBirdReactNativeSampleTests" */; - buildPhases = ( - 00E356EA1AD99517003FC87E /* Sources */, - 00E356EB1AD99517003FC87E /* Frameworks */, - 00E356EC1AD99517003FC87E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 00E356F51AD99517003FC87E /* PBXTargetDependency */, - ); - name = SendBirdReactNativeSampleTests; - productName = SendBirdReactNativeSampleTests; - productReference = 00E356EE1AD99517003FC87E /* SendBirdReactNativeSampleTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 13B07F861A680F5B00A75B9A /* SendBirdReactNativeSample */ = { - isa = PBXNativeTarget; - buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "SendBirdReactNativeSample" */; - buildPhases = ( - 13B07F871A680F5B00A75B9A /* Sources */, - 13B07F8C1A680F5B00A75B9A /* Frameworks */, - 13B07F8E1A680F5B00A75B9A /* Resources */, - 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = SendBirdReactNativeSample; - productName = "Hello World"; - productReference = 13B07F961A680F5B00A75B9A /* SendBirdReactNativeSample.app */; - productType = "com.apple.product-type.application"; - }; - 2D02E47A1E0B4A5D006451C7 /* SendBirdReactNativeSample-tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "SendBirdReactNativeSample-tvOS" */; - buildPhases = ( - 2D02E4771E0B4A5D006451C7 /* Sources */, - 2D02E4781E0B4A5D006451C7 /* Frameworks */, - 2D02E4791E0B4A5D006451C7 /* Resources */, - 2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "SendBirdReactNativeSample-tvOS"; - productName = "SendBirdReactNativeSample-tvOS"; - productReference = 2D02E47B1E0B4A5D006451C7 /* SendBirdReactNativeSample-tvOS.app */; - productType = "com.apple.product-type.application"; - }; - 2D02E48F1E0B4A5D006451C7 /* SendBirdReactNativeSample-tvOSTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "SendBirdReactNativeSample-tvOSTests" */; - buildPhases = ( - 2D02E48C1E0B4A5D006451C7 /* Sources */, - 2D02E48D1E0B4A5D006451C7 /* Frameworks */, - 2D02E48E1E0B4A5D006451C7 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */, - ); - name = "SendBirdReactNativeSample-tvOSTests"; - productName = "SendBirdReactNativeSample-tvOSTests"; - productReference = 2D02E4901E0B4A5D006451C7 /* SendBirdReactNativeSample-tvOSTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 83CBB9F71A601CBA00E9B192 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 610; - ORGANIZATIONNAME = Facebook; - TargetAttributes = { - 00E356ED1AD99517003FC87E = { - CreatedOnToolsVersion = 6.2; - TestTargetID = 13B07F861A680F5B00A75B9A; - }; - 13B07F861A680F5B00A75B9A = { - DevelopmentTeam = 8K8M9F9X95; - SystemCapabilities = { - com.apple.Push = { - enabled = 1; - }; - }; - }; - 2D02E47A1E0B4A5D006451C7 = { - CreatedOnToolsVersion = 8.2.1; - ProvisioningStyle = Automatic; - }; - 2D02E48F1E0B4A5D006451C7 = { - CreatedOnToolsVersion = 8.2.1; - ProvisioningStyle = Automatic; - TestTargetID = 2D02E47A1E0B4A5D006451C7; - }; - }; - }; - buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "SendBirdReactNativeSample" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 83CBB9F61A601CBA00E9B192; - productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; - projectDirPath = ""; - projectReferences = ( - { - ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */; - ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */; - }, - { - ProductGroup = 5E91572E1DD0AC6500FF2AA8 /* Products */; - ProjectRef = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */; - }, - { - ProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */; - ProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */; - }, - { - ProductGroup = 00C302BC1ABCB91800DB3ED1 /* Products */; - ProjectRef = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; - }, - { - ProductGroup = 78C398B11ACF4ADC00677621 /* Products */; - ProjectRef = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; - }, - { - ProductGroup = 00C302D41ABCB9D200DB3ED1 /* Products */; - ProjectRef = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */; - }, - { - ProductGroup = 2F66A0101E58ED7000D55F29 /* Products */; - ProjectRef = 2F66A00F1E58ED7000D55F29 /* RCTPushNotification.xcodeproj */; - }, - { - ProductGroup = 139105B71AF99BAD00B5F7CC /* Products */; - ProjectRef = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */; - }, - { - ProductGroup = 832341B11AAA6A8300B99B32 /* Products */; - ProjectRef = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; - }, - { - ProductGroup = 00C302E01ABCB9EE00DB3ED1 /* Products */; - ProjectRef = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */; - }, - { - ProductGroup = 139FDEE71B06529A00C62182 /* Products */; - ProjectRef = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; - }, - { - ProductGroup = 146834001AC3E56700842450 /* Products */; - ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */; - }, - { - ProductGroup = 2F66A06C1E599CE900D55F29 /* Products */; - ProjectRef = B79A3B3E02DC42649F3D3DAA /* RNFS.xcodeproj */; - }, - { - ProductGroup = 2F66A03F1E58F9FF00D55F29 /* Products */; - ProjectRef = DAA1237B9B154DEDB991C6D1 /* RNImagePicker.xcodeproj */; - }, - ); - projectRoot = ""; - targets = ( - 13B07F861A680F5B00A75B9A /* SendBirdReactNativeSample */, - 00E356ED1AD99517003FC87E /* SendBirdReactNativeSampleTests */, - 2D02E47A1E0B4A5D006451C7 /* SendBirdReactNativeSample-tvOS */, - 2D02E48F1E0B4A5D006451C7 /* SendBirdReactNativeSample-tvOSTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXReferenceProxy section */ - 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTActionSheet.a; - remoteRef = 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTGeolocation.a; - remoteRef = 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTImage.a; - remoteRef = 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTNetwork.a; - remoteRef = 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTVibration.a; - remoteRef = 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTSettings.a; - remoteRef = 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTWebSocket.a; - remoteRef = 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 146834041AC3E56700842450 /* libReact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libReact.a; - remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 2F66A01F1E58ED7000D55F29 /* libRCTPushNotification.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTPushNotification.a; - remoteRef = 2F66A01E1E58ED7000D55F29 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 2F66A0211E58ED7000D55F29 /* libRCTPushNotification-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTPushNotification-tvOS.a"; - remoteRef = 2F66A0201E58ED7000D55F29 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 2F66A05E1E58F9FF00D55F29 /* libRNImagePicker.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRNImagePicker.a; - remoteRef = 2F66A05D1E58F9FF00D55F29 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 2F66A08B1E599CE900D55F29 /* libRNFS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRNFS.a; - remoteRef = 2F66A08A1E599CE900D55F29 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTImage-tvOS.a"; - remoteRef = 3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTLinking-tvOS.a"; - remoteRef = 3DAD3E871DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTNetwork-tvOS.a"; - remoteRef = 3DAD3E8B1DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTSettings-tvOS.a"; - remoteRef = 3DAD3E8F1DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTText-tvOS.a"; - remoteRef = 3DAD3E931DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTWebSocket-tvOS.a"; - remoteRef = 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3EA31DF850E9000B6D8A /* libReact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libReact.a; - remoteRef = 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3EA51DF850E9000B6D8A /* libyoga.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libyoga.a; - remoteRef = 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3EA71DF850E9000B6D8A /* libyoga.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libyoga.a; - remoteRef = 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libcxxreact.a; - remoteRef = 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libcxxreact.a; - remoteRef = 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libjschelpers.a; - remoteRef = 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libjschelpers.a; - remoteRef = 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTAnimation.a; - remoteRef = 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTAnimation-tvOS.a"; - remoteRef = 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTLinking.a; - remoteRef = 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 832341B51AAA6A8300B99B32 /* libRCTText.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTText.a; - remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; -/* End PBXReferenceProxy section */ - -/* Begin PBXResourcesBuildPhase section */ - 00E356EC1AD99517003FC87E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 13B07F8E1A680F5B00A75B9A /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, - 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 2D02E4791E0B4A5D006451C7 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 2D02E48E1E0B4A5D006451C7 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Bundle React Native code and images"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh"; - }; - 2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Bundle React Native Code And Images"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 00E356EA1AD99517003FC87E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 00E356F31AD99517003FC87E /* SendBirdReactNativeSampleTests.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 13B07F871A680F5B00A75B9A /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, - 13B07FC11A68108700A75B9A /* main.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 2D02E4771E0B4A5D006451C7 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */, - 2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 2D02E48C1E0B4A5D006451C7 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 2DCD954D1E0B4F2C00145EB5 /* SendBirdReactNativeSampleTests.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 00E356F51AD99517003FC87E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 13B07F861A680F5B00A75B9A /* SendBirdReactNativeSample */; - targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */; - }; - 2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 2D02E47A1E0B4A5D006451C7 /* SendBirdReactNativeSample-tvOS */; - targetProxy = 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { - isa = PBXVariantGroup; - children = ( - 13B07FB21A68108700A75B9A /* Base */, - ); - name = LaunchScreen.xib; - path = SendBirdReactNativeSample; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 00E356F61AD99517003FC87E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - INFOPLIST_FILE = SendBirdReactNativeSampleTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - ); - OTHER_LDFLAGS = ( - "-ObjC", - "-lc++", - ); - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SendBirdReactNativeSample.app/SendBirdReactNativeSample"; - }; - name = Debug; - }; - 00E356F71AD99517003FC87E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COPY_PHASE_STRIP = NO; - INFOPLIST_FILE = SendBirdReactNativeSampleTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - ); - OTHER_LDFLAGS = ( - "-ObjC", - "-lc++", - ); - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SendBirdReactNativeSample.app/SendBirdReactNativeSample"; - }; - name = Release; - }; - 13B07F941A680F5B00A75B9A /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = SendBirdReactNativeSample/SendBirdReactNativeSample.entitlements; - CURRENT_PROJECT_VERSION = 1; - DEAD_CODE_STRIPPING = NO; - DEVELOPMENT_TEAM = 8K8M9F9X95; - HEADER_SEARCH_PATHS = "$(SRCROOT)/../node_modules/react-native/Libraries/PushNotificationIOS/**"; - INFOPLIST_FILE = SendBirdReactNativeSample/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - OTHER_LDFLAGS = ( - "$(inherited)", - "-ObjC", - "-lc++", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.sendbird.sample; - PRODUCT_NAME = SendBirdReactNativeSample; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 13B07F951A680F5B00A75B9A /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = SendBirdReactNativeSample/SendBirdReactNativeSample.entitlements; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 8K8M9F9X95; - HEADER_SEARCH_PATHS = "$(SRCROOT)/../node_modules/react-native/Libraries/PushNotificationIOS/**"; - INFOPLIST_FILE = SendBirdReactNativeSample/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - OTHER_LDFLAGS = ( - "$(inherited)", - "-ObjC", - "-lc++", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.sendbird.sample; - PRODUCT_NAME = SendBirdReactNativeSample; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; - 2D02E4971E0B4A5E006451C7 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_TESTABILITY = YES; - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = "SendBirdReactNativeSample-tvOS/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - ); - OTHER_LDFLAGS = ( - "-ObjC", - "-lc++", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.SendBirdReactNativeSample-tvOS"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TARGETED_DEVICE_FAMILY = 3; - TVOS_DEPLOYMENT_TARGET = 9.2; - }; - name = Debug; - }; - 2D02E4981E0B4A5E006451C7 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = "SendBirdReactNativeSample-tvOS/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - ); - OTHER_LDFLAGS = ( - "-ObjC", - "-lc++", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.SendBirdReactNativeSample-tvOS"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TARGETED_DEVICE_FAMILY = 3; - TVOS_DEPLOYMENT_TARGET = 9.2; - }; - name = Release; - }; - 2D02E4991E0B4A5E006451C7 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_TESTABILITY = YES; - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = "SendBirdReactNativeSample-tvOSTests/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.SendBirdReactNativeSample-tvOSTests"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SendBirdReactNativeSample-tvOS.app/SendBirdReactNativeSample-tvOS"; - TVOS_DEPLOYMENT_TARGET = 10.1; - }; - name = Debug; - }; - 2D02E49A1E0B4A5E006451C7 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = "SendBirdReactNativeSample-tvOSTests/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.SendBirdReactNativeSample-tvOSTests"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SendBirdReactNativeSample-tvOS.app/SendBirdReactNativeSample-tvOS"; - TVOS_DEPLOYMENT_TARGET = 10.1; - }; - name = Release; - }; - 83CBBA201A601CBA00E9B192 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - 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 = 8.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - }; - name = Debug; - }; - 83CBBA211A601CBA00E9B192 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = YES; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - 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 = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "SendBirdReactNativeSampleTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 00E356F61AD99517003FC87E /* Debug */, - 00E356F71AD99517003FC87E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "SendBirdReactNativeSample" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 13B07F941A680F5B00A75B9A /* Debug */, - 13B07F951A680F5B00A75B9A /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "SendBirdReactNativeSample-tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2D02E4971E0B4A5E006451C7 /* Debug */, - 2D02E4981E0B4A5E006451C7 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "SendBirdReactNativeSample-tvOSTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2D02E4991E0B4A5E006451C7 /* Debug */, - 2D02E49A1E0B4A5E006451C7 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "SendBirdReactNativeSample" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 83CBBA201A601CBA00E9B192 /* Debug */, - 83CBBA211A601CBA00E9B192 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; -} diff --git a/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample.xcodeproj/xcshareddata/xcschemes/SendBirdReactNativeSample-tvOS.xcscheme b/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample.xcodeproj/xcshareddata/xcschemes/SendBirdReactNativeSample-tvOS.xcscheme deleted file mode 100644 index a1623cc3..00000000 --- a/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample.xcodeproj/xcshareddata/xcschemes/SendBirdReactNativeSample-tvOS.xcscheme +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample.xcodeproj/xcshareddata/xcschemes/SendBirdReactNativeSample.xcscheme b/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample.xcodeproj/xcshareddata/xcschemes/SendBirdReactNativeSample.xcscheme deleted file mode 100644 index 751ff63b..00000000 --- a/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample.xcodeproj/xcshareddata/xcschemes/SendBirdReactNativeSample.xcscheme +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample/AppDelegate.h b/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample/AppDelegate.h deleted file mode 100644 index a9654d5e..00000000 --- a/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample/AppDelegate.h +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -#import - -@interface AppDelegate : UIResponder - -@property (nonatomic, strong) UIWindow *window; - -@end diff --git a/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample/AppDelegate.m b/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample/AppDelegate.m deleted file mode 100644 index e91f2f3f..00000000 --- a/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample/AppDelegate.m +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -#import "AppDelegate.h" - -#import "RCTPushNotificationManager.h" -#import -#import - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions -{ - NSURL *jsCodeLocation; - - jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; - - RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation - moduleName:@"SendBirdReactNativeSample" - initialProperties:nil - launchOptions:launchOptions]; - rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; - - self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; - UIViewController *rootViewController = [UIViewController new]; - rootViewController.view = rootView; - self.window.rootViewController = rootViewController; - [self.window makeKeyAndVisible]; - return YES; -} - -// Required to register for notifications -- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings -{ - [RCTPushNotificationManager didRegisterUserNotificationSettings:notificationSettings]; -} -// Required for the register event. -- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken -{ - [RCTPushNotificationManager didRegisterForRemoteNotificationsWithDeviceToken:deviceToken]; -} -// Required for the notification event. You must call the completion handler after handling the remote notification. -- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo -fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler -{ - [RCTPushNotificationManager didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler]; -} -// Required for the registrationError event. -- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error -{ - [RCTPushNotificationManager didFailToRegisterForRemoteNotificationsWithError:error]; -} -// Required for the localNotification event. -- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification -{ - [RCTPushNotificationManager didReceiveLocalNotification:notification]; -} - -@end diff --git a/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample/Base.lproj/LaunchScreen.xib b/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample/Base.lproj/LaunchScreen.xib deleted file mode 100644 index 97398f38..00000000 --- a/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample/Base.lproj/LaunchScreen.xib +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample/Images.xcassets/AppIcon.appiconset/Contents.json b/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample/Images.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index b8236c65..00000000 --- a/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample/Images.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample/Info.plist b/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample/Info.plist deleted file mode 100644 index f5d148d6..00000000 --- a/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample/Info.plist +++ /dev/null @@ -1,61 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleDisplayName - SendBirdReactNativeSample - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSRequiresIPhoneOS - - NSAppTransportSecurity - - NSExceptionDomains - - localhost - - NSExceptionAllowsInsecureHTTPLoads - - - - - NSCameraUsageDescription - This app requires access to the camera. - NSLocationWhenInUseUsageDescription - - NSMicrophoneUsageDescription - This app does not require access to the microphone. - NSPhotoLibraryUsageDescription - This app requires access to the photo library. - UILaunchStoryboardName - LaunchScreen - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample/main.m b/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample/main.m deleted file mode 100644 index 3d767fcb..00000000 --- a/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSample/main.m +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -#import - -#import "AppDelegate.h" - -int main(int argc, char * argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -} diff --git a/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSampleTests/SendBirdReactNativeSampleTests.m b/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSampleTests/SendBirdReactNativeSampleTests.m deleted file mode 100644 index 0bb03307..00000000 --- a/react-native-sample/SendBirdReactNativeSample/ios/SendBirdReactNativeSampleTests/SendBirdReactNativeSampleTests.m +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -#import -#import - -#import -#import - -#define TIMEOUT_SECONDS 600 -#define TEXT_TO_LOOK_FOR @"Welcome to React Native!" - -@interface SendBirdReactNativeSampleTests : XCTestCase - -@end - -@implementation SendBirdReactNativeSampleTests - -- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test -{ - if (test(view)) { - return YES; - } - for (UIView *subview in [view subviews]) { - if ([self findSubviewInView:subview matching:test]) { - return YES; - } - } - return NO; -} - -- (void)testRendersWelcomeScreen -{ - UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; - NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; - BOOL foundElement = NO; - - __block NSString *redboxError = nil; - RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { - if (level >= RCTLogLevelError) { - redboxError = message; - } - }); - - while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { - [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - - foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { - if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { - return YES; - } - return NO; - }]; - } - - RCTSetLogFunction(RCTDefaultLogFunction); - - XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); - XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); -} - - -@end diff --git a/react-native-sample/SendBirdReactNativeSample/package.json b/react-native-sample/SendBirdReactNativeSample/package.json deleted file mode 100644 index 51652d32..00000000 --- a/react-native-sample/SendBirdReactNativeSample/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "SendBirdReactNativeSample", - "version": "0.1.0", - "private": true, - "scripts": { - "start": "node node_modules/react-native/local-cli/cli.js start" - }, - "dependencies": { - "moment": "2.14.1", - "react": "16.0.0-alpha.6", - "react-native": "0.44.0", - "react-native-deprecated-custom-components": "0.1.0", - "react-native-button": "1.8.2", - "react-native-cacheable-image": "1.5.1", - "react-native-image-picker": "0.25.5", - "react-native-push-notification": "2.2.1", - "sendbird": "3.0.31" - } -} diff --git a/react-native-sample/SendBirdReactNativeSample/src/components/button.js b/react-native-sample/SendBirdReactNativeSample/src/components/button.js deleted file mode 100644 index 909df3bb..00000000 --- a/react-native-sample/SendBirdReactNativeSample/src/components/button.js +++ /dev/null @@ -1,45 +0,0 @@ -import React, { Component } from 'react'; -import { TouchableHighlight, Text } from 'react-native'; - -export default class Button extends Component { - constructor(props) { - super(props); - this.style = this.props.style; - } - render() { - return ( - - {this.props.text} - - ); - } - - _buttonStyle() { - return { - justifyContent: 'center', - alignItems: 'center', - borderWidth: 1, - borderRadius: 4, - borderColor: this.props.disabled ? this.style.disabledColor : this.style.borderColor, - padding: 10, - marginTop: 10, - backgroundColor: this.props.disabled ? this.style.disabledColor : this.style.backgroundColor - } - } - - _textStyle() { - return { - width: 230, - alignSelf: 'center', - textAlign: 'center', - fontSize: 20, - fontWeight: '600', - color: this.style.textColor - } - } -} diff --git a/react-native-sample/SendBirdReactNativeSample/src/components/imageButton.js b/react-native-sample/SendBirdReactNativeSample/src/components/imageButton.js deleted file mode 100644 index a1487570..00000000 --- a/react-native-sample/SendBirdReactNativeSample/src/components/imageButton.js +++ /dev/null @@ -1,20 +0,0 @@ -import React, { Component } from 'react'; -import { TouchableHighlight, Image } from 'react-native'; - -export default class ImageButton extends Component { - constructor(props) { - super(props); - this.style = this.props.style; - } - render() { - return ( - - - - ); - } -} diff --git a/react-native-sample/SendBirdReactNativeSample/src/components/topBar.js b/react-native-sample/SendBirdReactNativeSample/src/components/topBar.js deleted file mode 100644 index cf24a78e..00000000 --- a/react-native-sample/SendBirdReactNativeSample/src/components/topBar.js +++ /dev/null @@ -1,113 +0,0 @@ -import React, { Component } from 'react' -import { - View, - Text, - Image, - StyleSheet -} from 'react-native' - -import ImageButton from './imageButton'; - -var backIcon = require('../img/btn-back.png'); -var addIcon = require('../img/btn-add.png'); -var listIcon = require('../img/btn-list.png'); - -export default class TopBar extends Component { - constructor(props) { - super(props); - } - - render() { - return ( - - - - - - - {this.props.title} - - - - {this._renderButton()} - - - ); - } - - _renderButton() { - if (this.props.onCreateOpenChannel) { - return ( - - ) - } else if (this.props.onOpenMenu) { - return ( - - ) - } else if (this.props.onGroupChannel) { - return ( - - ) - } else if (this.props.onInvite) { - return ( - - ) - } - } - -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - flexDirection: 'row', - justifyContent: 'space-around', - alignItems: 'center', - backgroundColor: '#4e4273', - paddingTop: 20, - paddingBottom: 2, - }, - titleLabel: { - color:'#fff', - textAlign:'center', - fontWeight:'bold', - fontSize: 18 - }, - leftButton: { - justifyContent: 'flex-start', - paddingLeft: 5 - }, - rightButton: { - justifyContent: 'flex-end', - paddingRight: 10 - }, - imageButton: { - width: 30, - height: 30 - } -}); diff --git a/react-native-sample/SendBirdReactNativeSample/src/consts.js b/react-native-sample/SendBirdReactNativeSample/src/consts.js deleted file mode 100644 index 1ecfdc08..00000000 --- a/react-native-sample/SendBirdReactNativeSample/src/consts.js +++ /dev/null @@ -1,2 +0,0 @@ -export const APP_ID = '9DA1B1F4-0BE6-4DA8-82C5-2E81DAB56F23'; -export const PULLDOWN_DISTANCE = 40; diff --git a/react-native-sample/SendBirdReactNativeSample/src/img/btn-add.png b/react-native-sample/SendBirdReactNativeSample/src/img/btn-add.png deleted file mode 100644 index d18a0ff4..00000000 Binary files a/react-native-sample/SendBirdReactNativeSample/src/img/btn-add.png and /dev/null differ diff --git a/react-native-sample/SendBirdReactNativeSample/src/img/btn-back.png b/react-native-sample/SendBirdReactNativeSample/src/img/btn-back.png deleted file mode 100644 index 2b4d614a..00000000 Binary files a/react-native-sample/SendBirdReactNativeSample/src/img/btn-back.png and /dev/null differ diff --git a/react-native-sample/SendBirdReactNativeSample/src/img/btn-check.png b/react-native-sample/SendBirdReactNativeSample/src/img/btn-check.png deleted file mode 100644 index f06683b8..00000000 Binary files a/react-native-sample/SendBirdReactNativeSample/src/img/btn-check.png and /dev/null differ diff --git a/react-native-sample/SendBirdReactNativeSample/src/img/btn-list.png b/react-native-sample/SendBirdReactNativeSample/src/img/btn-list.png deleted file mode 100644 index 2b725397..00000000 Binary files a/react-native-sample/SendBirdReactNativeSample/src/img/btn-list.png and /dev/null differ diff --git a/react-native-sample/SendBirdReactNativeSample/src/main.js b/react-native-sample/SendBirdReactNativeSample/src/main.js deleted file mode 100644 index 92044575..00000000 --- a/react-native-sample/SendBirdReactNativeSample/src/main.js +++ /dev/null @@ -1,126 +0,0 @@ -import React, { Component } from 'react'; -import { - AppRegistry, - StyleSheet, - AppState, - Platform -} from 'react-native'; -import NavigationExperimental from 'react-native-deprecated-custom-components'; -import Login from './pages/login'; -import OpenChannel from './pages/openChannel'; -import CreateChannel from './pages/createChannel'; -import Chat from './pages/chat'; -import Participants from './pages/participants'; -import BlockList from './pages/blockList'; -import GroupChannel from './pages/groupChannel'; -import InviteUser from './pages/inviteUser'; -import Members from './pages/members' - -import {APP_ID} from './consts' -import SendBird from 'sendbird' -var sb = null; - - - -var ROUTES = { - login: Login, - openChannel: OpenChannel, - createChannel: CreateChannel, - chat: Chat, - participants: Participants, - blockList: BlockList, - groupChannel: GroupChannel, - inviteUser: InviteUser, - members: Members -}; - -export default class Main extends Component { - - _handleAppStateChange = (currentAppState) => { - if (currentAppState === 'active') { - console.log('appstate - foreground'); - if(sb){ - sb.setForegroundState(); - } - } else if (currentAppState === 'background') { - console.log('appstate - background'); - if(sb){ - sb.setBackgroundState(); - } - } - } - - componentDidMount() { - sb = new SendBird({appId: APP_ID}); - - AppState.addEventListener('change', this._handleAppStateChange); - var Notifications = require('react-native-push-notification'); - Notifications.configure({ - onRegister: function(token) { - if (Platform.OS === 'ios') { - sb.registerAPNSPushTokenForCurrentUser(token['token'], function(result, error){ - console.log("registerAPNSPushTokenForCurrentUser"); - console.log(result); - }); - } else { - sb.registerGCMPushTokenForCurrentUser(token['token'], function(result, error){ - console.log("registerAPNSPushTokenForCurrentUser"); - console.log(result); - }); - } - }, - - onNotification: function(notification) { - console.log( 'NOTIFICATION:', notification ); - }, - - // ANDROID ONLY: GCM Sender ID (optional - not required for local notifications, but is need to receive remote push notifications) - senderID: "984140644677", - - // IOS ONLY (optional): default: all - Permissions to register. - permissions: { - alert: true, - badge: true, - sound: true - }, - - // Should the initial notification be popped automatically - // default: true - popInitialNotification: true, - - /** - * (optional) default: true - * - Specified if permissions (ios) and token (android and ios) will requested or not, - * - if not, you must call PushNotificationsHandler.requestPermissions() later - */ - requestPermissions: true, - }); - - } - - componentWillUnmount() { - AppState.removeEventListener('change', this._handleAppStateChange); - } - - render() { - return ( - {return NavigationExperimental.Navigator.SceneConfigs.FloatFromRight;}} - style={styles.container} - /> - ) - } - - _renderScene(route, navigator) { - var Component = ROUTES[route.name]; - return ; - } -} - -const styles = StyleSheet.create({ - container: { - flex: 1 - } -}); diff --git a/react-native-sample/SendBirdReactNativeSample/src/pages/blockList.js b/react-native-sample/SendBirdReactNativeSample/src/pages/blockList.js deleted file mode 100644 index b08bce0e..00000000 --- a/react-native-sample/SendBirdReactNativeSample/src/pages/blockList.js +++ /dev/null @@ -1,157 +0,0 @@ -import React, { Component } from 'react' -import { - View, - Text, - Image, - ListView, - TouchableHighlight, - Alert, - StyleSheet -} from 'react-native' - -import {APP_ID, PULLDOWN_DISTANCE} from '../consts'; -import TopBar from '../components/topBar'; -import SendBird from 'sendbird'; -var sb = null; - -export default class BlockList extends Component { - constructor(props) { - super(props); - sb = SendBird.getInstance(); - var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); - this.state = { - channel: props.route.channel, - list: [], - dataSource: ds.cloneWithRows([]), - listQuery: sb.createBlockedUserListQuery() - }; - this._onUserPress = this._onUserPress.bind(this); - this._onBackPress = this._onBackPress.bind(this); - this._getBlockList = this._getBlockList.bind(this); - } - - componentWillMount() { - this._getBlockList(); - } - - _onUserPress(obj) { - var _SELF = this; - Alert.alert( - 'Unblock User', - null, - [ - {text: 'Unblock', onPress: () => { - sb.unblockUser(obj, function(response, error) { - if(error) { - console.log(error); - return; - } - - _SELF.setState({list: _SELF.state.list.filter((user) => { - return user.userId !== obj.userId; - })}, ()=> { - _SELF.setState({dataSource: _SELF.state.dataSource.cloneWithRows(_SELF.state.list)}); - }); - }); - }}, - {text: 'Cancel'} - ] - ) - } - - _getBlockList() { - var _SELF = this; - this.state.listQuery.next(function(response, error) { - if (error) { - if (response.length == 0) { - return; - } - console.log('Get Participant List Fail.', error); - return; - } - - _SELF.setState({list: _SELF.state.list.concat(response)}, () => { - _SELF.setState({dataSource: _SELF.state.dataSource.cloneWithRows(_SELF.state.list)}); - }); - }); - } - - _onBackPress() { - this.props.navigator.pop(); - } - - render() { - return ( - - - - - this._getBlockList()} - onEndReachedThreshold={PULLDOWN_DISTANCE} - dataSource={this.state.dataSource} - renderRow={(rowData) => - this._onUserPress(rowData)}> - - - - - - {rowData.nickname} - - - - } - /> - - - ) - } - -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'stretch', - backgroundColor: '#ffffff' - }, - listContainer: { - flex: 11, - justifyContent: 'center', - alignItems: 'stretch' - }, - listItem: { - flex: 1, - flexDirection: 'row', - justifyContent: 'center', - alignItems: 'center', - backgroundColor: '#f7f8fc', - borderBottomWidth: 0.5, - borderColor: '#D0DBE4', - padding: 5 - }, - listIcon: { - justifyContent: 'flex-start', - paddingLeft: 10, - paddingRight: 15 - }, - profileIcon: { - width: 30, - height: 30 - }, - listInfo: { - flex: 1, - justifyContent: 'flex-start' - }, - memberLabel: { - fontSize: 15, - fontWeight: '600', - color: '#60768b', - } -}); diff --git a/react-native-sample/SendBirdReactNativeSample/src/pages/chat.js b/react-native-sample/SendBirdReactNativeSample/src/pages/chat.js deleted file mode 100644 index f971d964..00000000 --- a/react-native-sample/SendBirdReactNativeSample/src/pages/chat.js +++ /dev/null @@ -1,507 +0,0 @@ -import React, { Component } from 'react' -import { - View, - Text, - Image, - TextInput, - TouchableHighlight, - StyleSheet, - PixelRatio, - Modal, - Alert, - Platform, - Keyboard, - KeyboardAvoidingView, - ListView -} from 'react-native' - -import CacheableImage from 'react-native-cacheable-image' -import {PULLDOWN_DISTANCE} from '../consts'; -import TopBar from '../components/topBar'; -import moment from 'moment'; -import Button from 'react-native-button'; - -// Android does keyboard height adjustment natively. -const ChatView = Platform.select({ - ios: () => KeyboardAvoidingView, - android: () => View, -})(); - -import SendBird from 'sendbird'; -var sb = null; -var ImagePicker = require('react-native-image-picker'); -var ipOptions = { - title: 'Select Image File To Send', - mediaType: 'photo', - noData: true -}; - -export default class Chat extends Component { - constructor(props) { - super(props); - sb = SendBird.getInstance(); - var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); - this.state = { - channel: props.route.channel, - name: props.route.name, - dataSource: ds.cloneWithRows([]), - messageQuery: props.route.channel.createPreviousMessageListQuery(), - messages: [], - text: '', - disabled: true, - show: false, - lastMessage: null, - hasRendered: false, - }; - this._onBackPress = this._onBackPress.bind(this); - this._onSend = this._onSend.bind(this); - this._onPhoto = this._onPhoto.bind(this); - this._onChangeText = this._onChangeText.bind(this); - this._onPressParticipants = this._onPressParticipants.bind(this); - this._onPressBlockList = this._onPressBlockList.bind(this); - } - - componentWillUnmount() { - sb.removeChannelHandler('ChatView'); - sb.removeConnectionHandler('ChatView') - } - - componentDidMount() { - var _SELF = this; - if (!_SELF.state.hasRendered){ - _SELF.state.hasRendered = true; - _SELF._getChannelMessage(false); - if (_SELF.state.channel.channelType == 'group') { - _SELF.state.channel.markAsRead(); - } - - // channel handler - var ChannelHandler = new sb.ChannelHandler(); - ChannelHandler.onMessageReceived = function(channel, message){ - if (channel.url == _SELF.state.channel.url) { - var _messages = []; - _messages.push(message); - var _newMessageList = _messages.concat(_SELF.state.messages); - _SELF.setState({ - messages: _newMessageList, - dataSource: _SELF.state.dataSource.cloneWithRows(_newMessageList) - }); - _SELF.state.lastMessage = message; - if (_SELF.state.channel.channelType == 'group') { - _SELF.state.channel.markAsRead(); - } - } - }; - - sb.addChannelHandler('ChatView', ChannelHandler); - - var ConnectionHandler = new sb.ConnectionHandler(); - ConnectionHandler.onReconnectSucceeded = function(){ - _SELF._getChannelMessage(true); - _SELF.state.channel.refresh(); - } - sb.addConnectionHandler('ChatView', ConnectionHandler); - } - } - - _getChannelMessage(refresh) { - var _SELF = this; - - if(refresh){ - _SELF.state.messageQuery = _SELF.props.route.channel.createPreviousMessageListQuery(); - _SELF.state.messages = []; - } - - if (!this.state.messageQuery.hasMore) { - return; - } - this.state.messageQuery.load(20, false, function(response, error){ - if (error) { - console.log('Get Message List Fail.', error); - return; - } - - var _messages = []; - for (var i = 0 ; i < response.length ; i++) { - var _curr = response[i]; - if (i > 0) { - var _prev = response[i-1]; - if (_curr.createdAt - _prev.createdAt > (1000 * 60 * 60)) { - if (i > 1 && !_messages[i-2].hasOwnProperty('isDate')) { - _messages.splice((i-1), 0, {isDate: true, createdAt: _prev.createdAt}); - } - } - } - _messages.push(_curr); - _SELF.state.lastMessage = _curr; - } - - var _newMessageList = _SELF.state.messages.concat(_messages.reverse()); - _SELF.setState({ - messages: _newMessageList, - dataSource: _SELF.state.dataSource.cloneWithRows(_newMessageList) - }); - }); - } - - _onPhoto() { - var _SELF = this; - - if (Platform.OS === 'android'){ - sb.disableStateChange(); - } - ImagePicker.showImagePicker(ipOptions, (response) => { - if (Platform.OS === 'android'){ - sb.enableStateChange(); - } - if (response.didCancel) { - console.log('User cancelled image picker'); - } - else if (response.error) { - console.log('ImagePicker Error: ', response.error); - } - else if (response.customButton) { - console.log('User tapped custom button: ', response.customButton); - } - else { - let source = {uri:response.uri}; - - if (response.name){ - source['name'] = response.fileName - } else{ - paths = response.uri.split("/") - source['name'] = paths[paths.length-1]; - } - - if (response.type){ - source['type'] = response.type; - } - - const CHECK_IMAGE_URI_INTERVAL = Platform.OS === 'android' ? 300 : 100; - - // This is needed to ensure that a file exists - setTimeout(() => { - // Use getSize as a proxy for when the image exists - Image.getSize( - response.uri, - () => { - _SELF.state.channel.sendFileMessage(source, function(message, error){ - if (error) { - console.log(error); - return; - } - - var _messages = []; - _messages.push(message); - if (_SELF.state.lastMessage && message.createdAt - _SELF.state.lastMessage.createdAt > (1000 * 60 * 60)) { - _messages.push({isDate: true, createdAt: message.createdAt}); - } - - var _newMessageList = _messages.concat(_SELF.state.messages); - _SELF.setState({ - messages: _newMessageList, - dataSource: _SELF.state.dataSource.cloneWithRows(_newMessageList) - }); - _SELF.state.lastMessage = message; - }); - } - ); - }, CHECK_IMAGE_URI_INTERVAL); - - }; - - }); - } - - _onSend() { - var _SELF = this; - if (!_SELF.state.text){ - return; - } - _SELF.state.channel.sendUserMessage(_SELF.state.text, '', function(message, error) { - if (error) { - console.log(error); - return; - } - - var _messages = []; - _messages.push(message); - if (_SELF.state.lastMessage && message.createdAt - _SELF.state.lastMessage.createdAt > (1000 * 60 * 60)) { - _messages.push({isDate: true, createdAt: message.createdAt}); - } - - var _newMessageList = _messages.concat(_SELF.state.messages); - _SELF.setState({ - messages: _newMessageList, - dataSource: _SELF.state.dataSource.cloneWithRows(_newMessageList) - }); - _SELF.state.lastMessage = message; - _SELF.setState({text: '', disabled: true}); - }); - } - - _onBackPress() { - var _SELF = this; - if(_SELF.state.channel.isOpenChannel()){ - _SELF.state.channel.exit(function(response, error){ - _SELF.props.route.refresh(); - _SELF.props.navigator.pop(); - }); - } else{ - _SELF.props.route.refresh(); - _SELF.props.navigator.pop(); - } - } - - _onOpenMenu() { - if (this.state.channel.channelType == 'open') { - Alert.alert( - 'Open Channel', - null, - [ - {text: 'Participant list', onPress: () => {this._onPressParticipants();}}, - {text: 'Blocked user list', onPress: () => {this._onPressBlockList();}}, - {text: 'Close'} - ] - ) - } else { - var _SELF = this; - Alert.alert( - 'Group Channel Event', - null, - [ - {text: 'Invite users to this channel', onPress: () => { - this.props.navigator.push({name: 'inviteUser', channel: this.state.channel}); - }}, - {text: 'Leave this channel', onPress: () => { - this.state.channel.leave(function(response, error) { - if (error) { - console.log(error); - return; - } - _SELF.props.navigator.pop(); - setTimeout(function() {_SELF.props.route._onHideChannel(_SELF.state.channel);}, 500); - }); - }}, - {text: 'Hide this channel', onPress: () => { - this.state.channel.hide(function(response, error) { - if (error) { - console.log(error); - return; - } - _SELF.props.navigator.pop(); - setTimeout(function() {_SELF.props.route._onHideChannel(_SELF.state.channel);}, 500); - }); - }}, - {text: 'Member list', onPress: () => { - _SELF.props.navigator.push({name: 'members', channel: _SELF.state.channel}); - }}, - {text: 'Close'} - ] - ) - } - } - - _onUserPress(obj) { - Alert.alert( - 'Block User', - null, - [ - {text: 'Block', onPress: () => { - sb.blockUser(obj, function(response, error) { - if(error) { - console.log(error); - return; - } - }) - }}, - {text: 'Cancel'} - ] - ) - } - - _onChangeText(text) { - this.setState({ - text: text, - disabled: (text.trim().length > 0) ? false : true - }) - } - - _onPressParticipants() { - this.setState({show: false}); - this.props.navigator.push({name: 'participants', channel: this.state.channel}); - } - _onPressBlockList() { - this.setState({show: false}); - this.props.navigator.push({name: 'blockList', channel: this.state.channel}); - } - - render() { - return ( - - - - this._getChannelMessage(false)} - onEndReachedThreshold={PULLDOWN_DISTANCE} - dataSource={this.state.dataSource} - renderRow={(rowData) => { - if (rowData.hasOwnProperty('isDate')) { - return ( - - {moment(rowData.createdAt).calendar()} - - ) - } else if (rowData.messageType == 'user') { - return ( - this._onUserPress(rowData.sender)}> - - - - - - {rowData.sender.nickname} - {rowData.message} - - - - ) - } else if (rowData.messageType == 'file') { - return ( - this._onUserPress(rowData.sender)}> - - - - - - {rowData.sender.nickname} - - - - - ) - } else if (rowData.messageType == 'admin') { - return ( - - - {rowData.message} - - - ) - } else { - return null - } - } - } - /> - - - - - - - - ) - } -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'stretch', - backgroundColor: '#ffffff' - }, - chatContainer: { - flex: 10, - justifyContent: 'center', - alignItems: 'stretch', - backgroundColor: '#f7f8fc' - }, - inputContainer: { - height: 44, - borderTopWidth: 1 / PixelRatio.get(), - borderColor: '#b2b2b2', - flexDirection: 'row', - paddingLeft: 10, - paddingRight: 10, - }, - textInput: { - alignSelf: 'center', - height: 30, - width: 100, - backgroundColor: '#FFF', - flex: 1, - padding: 0, - margin: 0, - fontSize: 15, - }, - photoButton: { - marginTop: 11, - marginRight: 10, - }, - sendButton: { - marginTop: 11, - marginLeft: 10, - }, - listItem: { - flex: 1, - flexDirection: 'row', - alignItems: 'flex-start', - backgroundColor: '#f7f8fc', - padding: 5, - }, - - adListItem: { - flex: 1, - flexDirection: 'row', - alignItems: 'flex-start', - backgroundColor: '#e6e9f0', - padding: 5, - margin: 5, - }, - - listIcon: { - justifyContent: 'flex-start', - paddingLeft: 10, - paddingRight: 15 - }, - senderIcon: { - width: 30, - height: 30 - }, - senderContainer: { - flex: 1, - flexDirection: 'column', - }, - senderText: { - fontSize: 12, - color: '#ababab' - }, - dateText: { - textAlign: 'center', - fontSize: 12, - color: '#ababab', - fontWeight: 'bold' - } -}); diff --git a/react-native-sample/SendBirdReactNativeSample/src/pages/createChannel.js b/react-native-sample/SendBirdReactNativeSample/src/pages/createChannel.js deleted file mode 100644 index 1529f2c3..00000000 --- a/react-native-sample/SendBirdReactNativeSample/src/pages/createChannel.js +++ /dev/null @@ -1,118 +0,0 @@ -import React, { Component } from 'react' -import { - View, - TextInput, - StyleSheet -} from 'react-native' - -import {APP_ID, PULLDOWN_DISTANCE} from '../consts'; -import SendBird from 'sendbird'; -var sb = null; - -import TopBar from '../components/topBar'; -import Button from '../components/button'; - -export default class CreateChannel extends Component { - constructor(props) { - super(props); - sb = SendBird.getInstance(); - this.state = { - channelName: '', - disable: true - }; - this._onChangeText = this._onChangeText.bind(this); - this._onBackPress = this._onBackPress.bind(this); - this._onPressCreateChannel = this._onPressCreateChannel.bind(this); - } - - _onChangeText(channelName) { - this.setState({ - channelName: channelName, - disable: (channelName.trim().length > 0) ? false : true - }) - } - - _onBackPress() { - this.props.navigator.pop(); - } - - _onPressCreateChannel() { - var _SELF = this; - sb.OpenChannel.createChannel(_SELF.state.channelName, '', '', [sb.currentUser.userId], function (channel, error) { - if (error) { - console.log('Create OpenChannel Fail.', error); - return; - } - channel.enter(function(response, error) { - if (error) { - console.log('Enter openChannel Fail.', error); - } - _SELF.props.navigator.replace({name: 'chat', channel: channel, refresh: _SELF.props.route.refresh}); - }) - }); - } - - _buttonStyle() { - return { - backgroundColor: '#6E5BAA', - underlayColor: '#51437f', - borderColor: '#6E5BAA', - disabledColor: '#ababab', - textColor: '#ffffff' - } - } - - render() { - return ( - - - - - - - - -
-
OPEN CHAT
-
Get started to select
a channel
-
- -
GROUP CHAT
-
-
- -
-
- -
- - - - - -
- -
- - -
-
-
- -
INVITE
- - -
- - -
-
- - -
-
- - -
-
WELCOME TO SAMPLE CHAT
-
-
- Create or select a channel to chat in.
- If you don't have a channel to participate,
- go ahead and create your first channel now. -
-
- - -
-
- -
-
-
- - -
- -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/index.html b/web-sample/index.html deleted file mode 100644 index 8394d578..00000000 --- a/web-sample/index.html +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - Web SDK Sample - - -
-
- - -
-
- - -
-
- -
-
- - -
-

- - -
- - -
- Start chatting on SendBird by choosing your display name.
- This can be changed anytime and will be shown on 1-on-1 and group messaging. -
-
- Download Sample -
- -
- - -
- -
-
-
- - -
- - - - - - - - - - - \ No newline at end of file diff --git a/web-sample/static/.DS_Store b/web-sample/static/.DS_Store deleted file mode 100644 index 7b04fe77..00000000 Binary files a/web-sample/static/.DS_Store and /dev/null differ diff --git a/web-sample/static/bootstrap/bootstrap.min.css b/web-sample/static/bootstrap/bootstrap.min.css deleted file mode 100644 index d65c66b1..00000000 --- a/web-sample/static/bootstrap/bootstrap.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! - * Bootstrap v3.3.5 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.33px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:3;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} \ No newline at end of file diff --git a/web-sample/static/bootstrap/bootstrap.min.js b/web-sample/static/bootstrap/bootstrap.min.js deleted file mode 100644 index 133aeecb..00000000 --- a/web-sample/static/bootstrap/bootstrap.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v3.3.5 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. - * Licensed under the MIT license - */ -if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.5",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.5",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),a(c.target).is('input[type="radio"]')||a(c.target).is('input[type="checkbox"]')||c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.5",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.5",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.5",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger("shown.bs.dropdown",h)}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),c.isInStateTrue()?void 0:(clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide())},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.5",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.5",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.5",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); \ No newline at end of file diff --git a/web-sample/static/css/sample-chat.css b/web-sample/static/css/sample-chat.css deleted file mode 100644 index 4822a533..00000000 --- a/web-sample/static/css/sample-chat.css +++ /dev/null @@ -1,1341 +0,0 @@ - -input, button, textarea { - outline: none; -} - -.left-nav::-webkit-scrollbar { - width: 8px; -} - -.left-nav::-webkit-scrollbar-track { - -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); - -webkit-border-radius: 10px; - border-radius: 10px; -} - -.left-nav::-webkit-scrollbar-thumb { - -webkit-border-radius: 10px; - border-radius: 10px; - background: rgba(63, 47, 91, 0.65); - -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.5); -} - -.left-nav::-webkit-scrollbar-thumb:window-inactive { - background: rgba(63, 47, 91, 0.65); -} - -.init-check { - display: none; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: rgba(0, 0, 0, 0.5); - z-index: 999; -} - -.sample-body { - min-width: 960px; - overflow-x: auto; -} - -.left-nav { - width: 220px; - height: 100vh; - background: #4e4273; - padding: 20px 0 0 0; - border-right: 1px solid #3b1973; - float: left; -} - -.left-nav-icon { - /*width: 142px;*/ - height: 50px; - background: url("../img/logo_SendBird_reversed.svg") no-repeat center center; - background-size: 160px; - background-position: 25%; - - margin-left: 14px; -} - -.left-nav-channel-select { - padding: 20px 14px 0 14px; -} - -.left-nav-button-guide { - width: 36px; - height: 36px; - background: url("../img/image-outerglow.svg") no-repeat center center transparent; - float: right; - margin-right: 7px; -} - -.left-nav-button { - width: 192px; - height: 40px; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; - padding: 0 0 0 14px; - font-family: 'Exo 2'; - font-weight: 400; - font-size: 13px; - color: #fff; - line-height: 36px; - border: 0; - text-align: left; -} - -.left-nav-open { - background: url("../img/btn-openchat-normal.svg") no-repeat 160px center #329fe6; -} -.left-nav-open:hover, -.left-nav-open:focus { - background: url("../img/btn-openchat-normal.svg") no-repeat 160px center #0e6bc4; -} - -.left-nav-open--active, -.left-nav-open--active:hover, -.left-nav-open--active:focus { - width: 212px; - background: url("../img/btn-openchat-close.svg") no-repeat 160px center #0e6bc4; -} - -.left-nav-messaging { - margin-top: 12px; - background: url("../img/btn-1on1groupchat-normal.svg") no-repeat 160px center #32c5e6; -} -.left-nav-messaging:hover, -.left-nav-messaging:focus { - background: url("../img/btn-1on1groupchat-normal.svg") no-repeat 160px center #0f9ab8; -} - -.left-nav-messaging--active, -.left-nav-messaging--active:hover, -.left-nav-messaging--active:focus { - width: 212px; - background: url("../img/btn-openchat-close.svg") no-repeat 160px center #0f9ab8; -} - -.left-nav-channel-section { - height: calc(100% - 240px); - margin-top: 18px; - overflow-y: auto; -} - -.left-nav-channel-empty { - width: 192px; - height: 72px; - padding: 18px 0 0 14px; - margin-left: 14px; - border: 1px dashed #7f6da0; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - font-family: 'Lato'; - font-weight: 500; - font-size: 14px; - color: #7f6da0; - line-height: 18px; - text-align: left; -} - -.left-nav-channel-title { - width: 100%; - height: 30px; - font-family: 'Lato'; - font-weight: 500; - font-size: 11px; - color: #7f6da0; - line-height: 30px; - padding: 0 14px; -} -.title-messaging { - margin-top: 18px; -} - -.left-nav-channel { - width: 100%; - font-family: 'Lato'; - font-weight: 500; - font-size: 16px; - color: #a08dce; - padding: 0 0 0 44px; - cursor: pointer; -} - -.left-nav-channel-lastmessage { - font-size: 13px; - color: #7f6da0; -} -.left-nav-channel-lastmessagetime { - font-size: 13px; - color: #7f6da0; - text-align: left; - padding-right: 20px; -} - -.left-nav-channel-open { - background: url("../img/icon-menu-channel-off.svg") no-repeat 14px center transparent; - margin-bottom: 4px; -} -.left-nav-channel-open:hover { - background: url("../img/icon-menu-channel-off.svg") no-repeat 14px center #463c66; -} - -.left-nav-channel-open--active { - background: url("../img/icon-menu-channel-on.svg") no-repeat 14px center #362f4f; - color: #fff; -} -.left-nav-channel-open--active:hover { - background: url("../img/icon-menu-channel-on.svg") no-repeat 14px center #3f2f5b; - color: #fff; -} - -.left-nav-channel-open--active:hover > .left-nav-channel-leave, -.left-nav-channel-messaging--active:hover > .left-nav-channel-leave, -.left-nav-channel-group--active:hover > .left-nav-channel-leave { - display: block; -} -.left-nav-channel-leave { - display: none; - width: 17px; - height: 30px; - float: right; - margin-right: 20px; - background: url("../img/btn-leave-menu-over.svg") no-repeat center center transparent; -} -.left-nav-channel-leave--active { - display: block; - background: url("../img/btn-leave-menu-click.svg") no-repeat center center transparent; -} - -.left-nav-channel-messaging { - background: url("../img/icon-menu-chat-off.svg") no-repeat 14px center transparent; -} -.left-nav-channel-messaging:hover { - background: url("../img/icon-menu-chat-off.svg") no-repeat 14px center #463c66; -} - -.left-nav-channel-messaging--active { - background: url("../img/icon-menu-chat-on.svg") no-repeat 14px center #362f4f; - color: #fff; -} - -.left-nav-channel-group { - background-repeat: no-repeat; - background-size: 24px; - background-position: left top; - background-color: transparent; - background-image: url("../img/icon-menu-group-off.svg"); - background-position-x: 10px; - background-position-y: 5px; - margin-bottom: 14px; - min-height: 35px; -} -.left-nav-channel-group:hover { - background-repeat: no-repeat; - background-size: 24px; - background-color: #463c66; - background-position-x: 10px; -} - -.left-nav-channel-group--active { - background-repeat: no-repeat; - background-size: 24px; - background-color: #362f4f; - background-position-x: 10px; - color: #fff; -} - -.left-nav-channel__unread { - width: 20px; - height: 16px; - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; - background: #f5429c; - font-family: 'Lato'; - font-weight: 400; - font-size: 11px; - color: #fff; - line-height: 16px; - float: right; - text-align: center; - margin: 7px 20px 0 0; -} - -.left-nav-user { - width: 220px; - height: 72px; - position: absolute; - bottom: 0; - background: #463c66; - font-family: 'Lato'; -} - -.left-nav-user-icon { - width: 30px; - height: 72px; - position: relative; - background: url("../img/image-profile.svg") no-repeat center center; - margin-left: 20px; - float: left; -} - -.left-nav-user-title { - width: auto; - height: auto; - position: relative; - font-weight: 500; - color: #7f6da0; -} - -.left-nav-user-nickname { - width: auto; - height: auto; - position: relative; - font-weight: 600; - color: #a08dce; -} - -.left-nav-login-user { - width: auto; - height: auto; - position: relative; - float: left; - margin-top: 14px; - margin-left: 12px; -} - - -.right-section { - width: calc(100% - 220px); - height: 100vh; - float: left; -} - -.right-section__modal-bg { - display: none; - width: calc(100% - 220px); - height: 100%; - z-index: 1; - background: rgba(0, 0, 0, 0.7); - position: absolute; -} - -.chat-top { - width: 100%; - height: 72px; - background: #fff; - border-bottom: 1px solid rgba(171, 184, 196, 0.5); - padding: 21px 20px 0 20px; -} - -.chat-top__title { - display: none; - padding-left: 20px; - background: url("../img/icon-openchat-title.svg") no-repeat left center; - font-family: 'Lato'; - font-weight: 500; - font-size: 18px; - color: #4f398f; - line-height: 30px; - float: left; -} -.chat-top__title--messaging { - background: url("../img/icon-1on1chat-title.svg") no-repeat left center; -} -.chat-top__title--group { - background: url("../img/icon-groupchat-title.svg") no-repeat left center; -} - -.chat-top-button { - display: none; - float: right; - height: 30px; -} - -.chat-top__button { - width: 30px; - height: 30px; - padding: 4px; - border: 1px solid #8f9fae; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; - cursor: pointer; - float: left; -} -.chat-top__button:hover { - -} - -.chat-top__button-hide { - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; - border-right: 0; - - display: none; - -webkit-border-top-left-radius: 0; - border-top-left-radius: 0; - -webkit-border-bottom-left-radius: 0; - border-bottom-left-radius: 0; - background: url("../img/btn-hide-normal.svg") no-repeat center center #f7f8fc; -} -.chat-top__button-hide:hover { - background: url("../img/btn-hide-over.svg") no-repeat center center #f7f8fc; -} - -.chat-top__button-leave { - -webkit-border-top-left-radius: 0; - border-top-left-radius: 0; - -webkit-border-bottom-left-radius: 0; - border-bottom-left-radius: 0; - background: url("../img/btn-leave-normal.svg") no-repeat center center #f7f8fc; -} -.chat-top__button-leave:hover { - background: url("../img/btn-leave-over.svg") no-repeat center center #f7f8fc; -} -.chat-top__button-leave--active { - background: url("../img/btn-leave-over.svg") no-repeat center center #e8eaef; -} - -.chat-top__button-member { - background: url("../img/btn-memberlist-normal.svg") no-repeat center center #f7f8fc; -} -.chat-top__button-member__right { - -webkit-border-top-right-radius: 0; - border-top-right-radius: 0; - -webkit-border-bottom-right-radius: 0; - border-bottom-right-radius: 0; - border-right: 0; -} -.chat-top__button-member__all { - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; - border-right: 0; - border-left: 0; -} -.chat-top__button-member:hover { - background: url("../img/btn-memberlist-over.svg") no-repeat center center #f7f8fc; -} -.chat-top__button-member--active { - background: url("../img/btn-memberlist-over.svg") no-repeat center center #e8eaef -} - -.chat-top__button-invite { - display: none; - width: 78px; - height: 30px; - -webkit-border-top-right-radius: 0; - border-top-right-radius: 0; - -webkit-border-bottom-right-radius: 0; - border-bottom-right-radius: 0; - font-family: 'Exo 2'; - font-weight: 400; - font-size: 12px; - color: #8f9fae; - line-height: 28px; - background: url("../img/btn-invite-normal.svg") no-repeat 8px center #f7f8fc; - padding: 0 0 0 26px; -} -.chat-top__button-invite:hover { - background: url("../img/btn-invite-over.svg") no-repeat 8px center #f7f8fc; -} -.chat-top__button-invite--active, -.chat-top__button-invite--active:hover { - color: #747f8d; - background: url("../img/btn-invite-normal.svg") no-repeat 8px #e8eaef; -} - -.chat-empty { - width: 100%; - height: calc(100% - 72px); - background: #f7f8fc; - padding: 190px 0; - font-family: 'Exo 2'; - font-weight: 400; - text-align: center; - color: #abb8c4; -} -.chat-empty__tile { - height: auto; - padding: 0; - font-size: 24px; -} -.chat-empty__icon { - width: 100%; - height: 66px; - padding: 0; - background: url("../img/img-empty.svg") no-repeat center center transparent; - margin: 20px 0; -} -.chat-empty__desc { - height: auto; - padding: 0; - font-size: 14px; -} - -.chat { - display: none; - width: 100%; - height: calc(100% - 72px); -} - -.chat-canvas { - width: 100%; - height: calc(100% - 71px); - background: #f7f8fc; - border-bottom: 1px solid rgba(171, 184, 196, 0.5); - overflow-y: auto; - padding: 28px 0 0 0; -} - -.chat-canvas__list { - width: 100%; - min-height: 24px; - background: transparent; - font-family: 'Lato'; - font-weight: 400; - font-size: 16px; - color: #60768b; - padding: 0 20px; -} -.chat-canvas__list:hover { - background-color: #efefef; -} - -/*label.chat-canvas__list-name:hover {*/ - /*cursor: pointer;*/ -/*}*/ -/*label.chat-canvas__list-text:hover {*/ - /*cursor: pointer;*/ -/*}*/ - -.chat-canvas__list-notice { - width: 100%; - height: 32px; - min-height: 24px; - background: transparent; - font-family: 'Lato'; - font-weight: 400; - font-size: 16px; - color: #60768b; - line-height: 24px; -} - -.chat-canvas__list-system { - width: 100%; - height: 24px; - font-weight: 400; - font-style: italic; - color: #60768b; - background: #e8ecef; - padding: 0 20px; - margin: 6px 0; -} - -.chat-canvas__list-broadcast { - width: 100%; - font-weight: 400; - font-style: normal; - color: #333e4a; - background: #d7eef7; - padding: 0 20px; - margin: 6px 0; -} - -.chat-canvas__list-name { - cursor: pointer; - font-weight: 600; - color: #333e4a; - vertical-align: top; -} -.chat-canvas__list-name__user { - color: #4f398f; -} -.chat-canvas__list-separator { - padding: 0 6px; - color: #60768b; - vertical-align: top; - font-weight: 400; -} -.chat-canvas__list-text { - cursor: pointer; - max-width: calc(100% - 220px); - color: #2a78c2; - word-wrap: break-word; - font-weight: 400; - font-size: 16px; - color: #60768b; -} -.chat-canvas__list-readreceipt { - font-size: 10px; - color: white; - display: none; - background-color: #75daeb; - border-radius: 10px; - /*border: 5px;*/ - width: 14px; - height: 14px; - line-height: 130%; - vertical-align: middle; - text-align: center; - margin: 0 0 0 5px; -} -.chat-canvas__list-text-file { - width: 44px; - margin-right: 6px; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; - background: #e2eff7; - font-family: 'Exo 2'; - font-weight: 400; - font-size: 12px; - color: #2a78c2; - text-align: center; -} -a.hover, -a:hover, -a.hover:hover { - color: #2a78c2; - text-decoration: underline; -} -.chat-canvas__list-file { - border-left: 4px solid #abb8c4; - padding-left: 10px; - cursor: pointer; - margin: 6px 0 10px 0; -} -.chat-canvas__list-file-img { - max-width: 400px; - max-height: 300px; -} - -.chat-input { - width: 100%; - height: 51px; - padding: 8px 20px 4px 20px; - background: #fff; -} - -.chat-input-file { - width: 40px; - height: 40px; - float: left; - padding: 10px; - margin-bottom: 3px; - border: 1px solid #abb8c4; - -webkit-border-top-left-radius: 2px; - border-top-left-radius: 2px; - -webkit-border-bottom-left-radius: 2px; - border-bottom-left-radius: 2px; - background: url("../img/btn-upload.svg") no-repeat center center; - cursor: pointer; -} -.chat-input-file:hover { - background: url("../img/btn-upload.svg") no-repeat center center #f7f8fc; -} - -.file-upload { - background: url("../img/loading-rectagular.gif") no-repeat center center #f7f8fc; -} -label.chat-input-file.file-upload { - background: url("../img/loading-rectagular.gif") no-repeat center center #f7f8fc; -} - -.chat-input-text { - width: calc(100% - 40px); - height: 40px; - float: left; -} - -.chat-input-typing { - display: none; - font-family: 'Lato'; - font-weight: 400; - font-style: italic; - font-size: 11px; - color: #60768b; - margin: 0; - padding: 0 20px; -} - -::-webkit-input-placeholder { /* WebKit browsers */ - font-weight: 300; -} -:-moz-placeholder { /* Mozilla Firefox 4 to 18 */ - font-weight: 300; -} -::-moz-placeholder { /* Mozilla Firefox 19+ */ - font-weight: 300; -} -:-ms-input-placeholder { /* Internet Explorer 10+ */ - font-weight: 300; -} -.chat-input-text__field { - width: 100%; - height: 40px; - min-height: 40px; - max-height: 40px; - font-family: 'Lato'; - font-weight: 400; - font-size: 14px; - color: #8f9fae; - overflow-y: auto; - resize: none; - padding: 10px 20px 0 20px; - border: 1px solid #abb8c4; - border-left: 0; - -webkit-border-top-right-radius: 2px; - border-top-right-radius: 2px; - -webkit-border-bottom-right-radius: 2px; - border-bottom-right-radius: 2px; - background: #f7f8fc; -} - -.chat-input-text__field:focus { - color: #60768b; - background: #fff; -} - -.modal-guide-create { - width: 316px; - height: 148px; - position: absolute; - top: 90px; - left: 230px; - border: 0; - background: url("../img/img-create.svg") no-repeat center center transparent; - padding: 20px 0 16px 0; - text-align: center; - z-index: 2; -} - -.modal-guide-create__title { - font-family: 'Lato'; - font-weight: 500; - font-size: 16px; - color: #32c5e6; -} - -.modal-guide-create__desc { - font-family: 'Lato'; - font-weight: 400; - font-size: 14px; - color: #fff; - margin: 10px 0; -} - -.modal-guide-create__button { - width: 76px; - height: 32px; - background: #32c5e6; - border: 1px solid #0692b0; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; - font-family: 'Exo 2'; - font-weight: 400; - font-size: 14px; - color: #fff; -} -.modal-guide-create__button:hover, -.modal-guide-create__button:focus { - background: #328fe6; - border: 1px solid #1a64ab; -} - -.modal-guide-leave { - display: none; - width: 62px; - height: 42px; - position: absolute; - top: 52px; - right: 16px; - border: 0; - background: url("../img/img-leave.svg") no-repeat center center transparent; - font-family: 'Lato'; - font-weight: 500; - font-size: 14px; - color: #fff; - line-height: 46px; - text-align: center; - z-index: 5; -} -.chat-top__button-leave:hover + .modal-guide-leave { - display: block; -} - -.modal-guide-member { - display: none; - width: 132px; - height: 42px; - position: absolute; - top: 52px; - right: 18px; - border: 0; - background: url("../img/img-current.svg") no-repeat center center transparent; - font-family: 'Lato'; - font-weight: 500; - font-size: 12px; - color: #fff; - line-height: 46px; - text-align: center; - z-index: 5; -} -.chat-top__button-member:hover + .modal-guide-member { - display: block; -} -.chat-top__button-member--active:hover + .modal-guide-member { - display: none; -} - -.modal-guide-user { - display: none; - width: 132px; - height: 42px; - position: absolute; - top: 52px; - right: 42px; - border: 0; - background: url("../img/img-member.svg") no-repeat center center transparent; - font-family: 'Lato'; - font-weight: 500; - font-size: 14px; - color: #fff; - line-height: 46px; - text-align: center; - z-index: 5; -} -.chat-top__button-invite:hover + .modal-guide-user { - display: block; -} -.chat-top__button-invite--active:hover + .modal-guide-user { - display: none; -} - -.modal-open-chat { - display: none; - width: 300px; - height: 100vh; - position: absolute; - background: #fff; - top: 0; - left: 220px; - z-index: 2; -} - -.modal-open-chat-top { - height: 72px; - padding: 20px 24px; - border-bottom: 1px solid rgba(171, 184, 196, 0.5); -} - -.modal-open-chat-top__search { - width: 250px; - height: 32px; - padding: 0 34px 0 12px; - background: url("../img/icon-search.svg") no-repeat 220px center #fff; - font-family: 'Lato'; - font-weight: 400; - font-size: 14px; - color: #abb8c4; - border: 1px solid #abb8c4; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; -} - -.modal-open-chat-top__search:hover { - background: url("../img/icon-search.svg") no-repeat 220px center #fafcff; - border: 1px solid #abb8c4; -} - -.modal-open-chat-top__search:focus { - background: url("../img/icon-search.svg") no-repeat 220px center #fff; - border: 1px solid #6742d6; - color: #60768b; -} - -.modal-open-chat-list { - width: 100%; - height: calc(100% - 163px); - overflow-y: auto; -} - -.modal-open-chat-list__item { - width: 100%; - height: 36px; - background: 20px center transparent; - font-family: 'Lato'; - font-weight: 400; - font-size: 16px; - color: #60768b; - line-height: 36px; - padding: 0 0 0 10px; - cursor: pointer; - overflow-y: hidden; - word-break: break-all; -} -.modal-open-chat-list__item:hover { - background: 20px center #e4ebef; - font-weight: 600; - color: #333e4a; -} -.modal-open-chat-list__item img { - width: 30px; - height: 30px; - border-radius: 50%; -} - -.modal-open-chat-more { - display: none; - width: 100%; - height: 72px; - border-top: 1px solid rgba(171, 184, 196, 0.5); - font-family: 'Lato'; - font-weight: 400; - font-size: 14px; - color: #60678b; - line-height: 36px; - text-align: center; - padding: 12px 15px; -} -.modal-open-chat-more__icon { - width: 10px; - height: 10px; - background: url("../img/btn-more-normal.svg") no-repeat center center; - margin-left: 6px; - display: inline-block; -} -.modal-open-chat-more:hover, -.modal-open-chat-more:focus { - color: #32c5e6; -} -.modal-open-chat-more:hover > .modal-open-chat-more__text > .modal-open-chat-more__icon, -.modal-open-chat-more:focus > .modal-open-chat-more__text > .modal-open-chat-more__icon { - background: url("../img/btn-more-over.svg") no-repeat center center; -} - -.modal-open-chat-more__text { - width: 270px; - height: 46px; - margin: auto; - font-family: 'Lato'; - font-weight: 400; - font-size: 14px; - color: #60678b; - line-height: 46px; - text-align: center; - background: #fff; - cursor: pointer; -} - -.modal-open-chat-more:hover > .modal-open-chat-more__text, -.modal-open-chat-more:focus > .modal-open-chat-more__text { - color: #32c5e6; - background: #f5f6f7; -} - -.modal-messaging { - display: none; - width: 300px; - height: 100vh; - position: absolute; - background: #fff; - top: 0; - left: 220px; - z-index: 2; -} -.modal-messaging-top { - width: 100%; - min-height: 48px; - padding: 16px 20px 0 20px; - font-family: 'Lato'; - font-weight: 500; - border-bottom: 1px solid rgba(171, 184, 196, 0.5); -} -.modal-messaging-top__title { - font-size: 16px; - color: #333e4a; -} -.modal-messaging-top__desc { - font-style: italic; - font-size: 14px; - font-weight: 300; - color: #abb8c4; -} - -.modal-messaging-top__btn{ - position: absolute; - right: 10px; - - border: 1px solid #4e4273; - color: #4e4273; - background-color: #f7f8fc; - background: url("../img/icon-create-channel.svg") no-repeat 20px center #fff; - background-position: center center; - width: 26px; - height: 26px; -} - -.modal-messaging-list { - width: 100%; - height: calc(100% - 164px); - overflow-y: auto; -} -.modal-messaging-list__item { - width: 100%; - height: 36px; - padding: 0 20px 0 50px; - background: url("../img/icon-userlist.svg") no-repeat 20px center #fff; - font-family: 'Lato'; - font-weight: 400; - font-size: 16px; - color: #60768b; - line-height: 36px; - cursor: pointer; -} -.modal-messaging-list__item:hover, -.modal-messaging-list__item:focus { - font-weight: 600; - background: url("../img/icon-userlist.svg") no-repeat 20px center #e4ebef; -} -.modal-messaging-list__icon { - width: 16px; - height: 36px; - float: right; - background: url("../img/btn-check-normal.svg") no-repeat center center; -} -.modal-messaging-list__item:hover > .modal-messaging-list__icon, -.modal-messaging-list__item:focus > .modal-messaging-list__icon { - background: url("../img/btn-check-over.svg") no-repeat center center; -} -.modal-messaging-list__icon--select, -.modal-messaging-list__item:hover > .modal-messaging-list__icon--select, -.modal-messaging-list__item:focus > .modal-messaging-list__icon--select { - background: url("../img/btn-check-click.svg") no-repeat center center; -} -.modal-messaging-more { - width: 100%; - height: 46px; - font-family: 'Lato'; - font-weight: 400; - font-size: 14px; - color: #60678b; - line-height: 46px; - text-align: center; - cursor: pointer; -} -.modal-messaging-more:hover, -.modal-messaging-more:focus { - color: #32c5e6; -} -.modal-messaging-more__icon { - width: 10px; - height: 10px; - background: url("../img/btn-more-normal.svg") no-repeat center center; - margin-left: 6px; - display: inline-block; -} -.modal-messaging-more:hover > .modal-messaging-more__icon, -.modal-messaging-more:focus > .modal-messaging-more__icon { - background: url("../img/btn-more-over.svg") no-repeat center center; -} -.modal-messaging-bottom { - width: 100%; - height: 72px; - border-top: 1px solid rgba(171, 184, 196, 0.5); - text-align: center; - padding: 13px 0; -} -.modal-messaging-bottom__button { - width: 270px; - height: 46px; - border: 1px solid #0692b0; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - font-family: 'Exo 2'; - font-weight: 400; - font-size: 16px; - color: #ffffff; - background: #32c5e6; -} -.modal-messaging-bottom__button:hover, -.modal-messaging-bottom__button:focus { - border: 1px solid #1a64ab; - background: #328fe6; -} - -.modal-leave-channel, .modal-hide-channel, .modal-confirm, .modal-input { - display: none; - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - width: 100%; - height: 100%; - background: rgba(0, 0, 0, 0.5); - opacity: 1; - z-index: 3; - -webkit-transition: opacity .15s linear; - -o-transition: opacity .15s linear; - transition: opacity .15s linear; -} - -.modal-leave-channel-card, .modal-hide-channel-card, .modal-confirm-card, .modal-input-card { - width: 386px; - height: auto; - margin: 200px auto; - background: #fff; - opacity: 1; - border: 1px solid #abb8c4; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} - -.modal-leave-channel-title, .modal-hide-channel-title, .modal-confirm-title, .modal-input-title { - font-family: 'Lato'; - font-weight: 600; - font-size: 18px; - color: #333e4a; - margin-top: 15px; - padding: 0 20px; -} - -.modal-leave-channel-desc, .modal-hide-channel-desc, .modal-confirm-desc, .modal-input-desc { - font-family: 'Lato'; - font-weight: 400; - font-size: 14px; - color: #60768b; - margin-top: 10px; - padding: 0 20px; -} - -.modal-leave-channel-separator, .modal-hide-channel-seprator, .modal-confirm-seprator, .modal-input-separator { - padding-top: 14px; - border-bottom: 1px solid rgba(171, 184, 196, 0.5); -} - -.modal-leave-channel-bottom, .modal-hide-channel-bottom, .modal-confirm-bottom, .modal-input-bottom { - padding: 10px 20px; - text-align: right; -} - -.modal-leave-channel-button, .modal-hide-channel-button, .modal-confirm-button, .modal-input-button { - width: 68px; - height: 28px; - text-align: center; - font-family: 'Exo 2'; - font-weight: 400; - font-size: 12px; - border: 1px solid; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; -} - -.modal-leave-channel-close, .modal-hide-channel-close, .modal-confirm-close, .modal-input-close { - color: #60678b; - border: 1px solid #abb8c4; - background: #fafcff; -} -.modal-leave-channel-close:hover, .modal-hide-channel-close:hover, .modal-confirm-close:hover, .modal-input-close:hover, -.modal-leave-channel-close:focus, .modal-hide-channel-close:focus, .modal-confirm-close:focus, .modal-input-close:focus { - color: #6742d6; - border: 1px solid #6742d6; -} - -.modal-leave-channel-submit, .modal-hide-channel-submit, .modal-confirm-submit, .modal-input-submit { - width: 58px; - color: #fff; - border: 1px solid #0692b0; - background: #32c5e6; -} -.modal-leave-channel-submit:hover, .modal-hide-channel-submit:hover, .modal-confirm-submit:hover, .modal-input-submit:hover, -.modal-leave-channel-submit:focus, .modal-hide-channel-submit:focus, .modal-confirm-submit:focus, .modal-input-submit:focus { - border: 1px solid #1a64ab; - background: #328fe6; -} - -.modal-input-box { - width: 100%; - padding: 0 20px 0 20px; -} - -.modal-input-box-elem { - width: 100%; - background-color: #F8F8F8; - border-radius: 3px; - border: 1px solid #dedede; - height: 30px; - padding-left: 12px; -} - -.modal-member { - display: none; - width: 250px; - height: 410px; - position: absolute; - top: 56px; - right: 48px; - background: #fff; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - border: 1px solid #abb8c4; - z-index: 2; - -webkit-box-shadow: 0 5px 10px 0 rgba(0,0,0,0.3); - -moz-box-shadow: 0 5px 10px 0 rgba(0,0,0,0.3); - box-shadow: 0 5px 10px 0 rgba(0,0,0,0.3); -} - -.modal-member-title { - width: 100%; - height: 38px; - font-family: 'Exo 2'; - font-weight: 400; - font-size: 12px; - color: #60768b; - border-bottom: 1px solid #abb8c4; - border-bottom: 1px solid rgba(171, 184, 196, 0.5); - padding: 0 20px; - line-height: 38px; -} - -.modal-member-list { - width: 100%; - height: 340px; - font-family: 'Lato'; - font-weight: 500; - font-size: 14px; - color: #60768b; - padding: 0 0 14px 0; - margin-top: 14px; - overflow-y: auto; -} - -.modal-member-list__item { - padding: 0 20px 14px 20px; -} - -.modal-member-list__icon img { - width: 23px; - height: 23px; - float: left; - margin-right: 10px; -} - -.modal-member-list__name { - width: auto; - height: 23px; - line-height: 23px; - color: #cdcdcd; -} - -.modal-member-list__name.online { - color: #60768b; -} - -.modal-member-list__lastseenat { - text-align: right; - font-size: 10pt; - color: #cdcdcd; -} - -.modal-invite { - display: none; - width: 386px; - height: 410px; - position: absolute; - top: 56px; - right: 80px; - background: #fff; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - border: 1px solid #abb8c4; - z-index: 2; - -webkit-box-shadow: 0 5px 10px 0 rgba(0,0,0,0.3); - -moz-box-shadow: 0 5px 10px 0 rgba(0,0,0,0.3); - box-shadow: 0 5px 10px 0 rgba(0,0,0,0.3); -} - -.modal-invite-title { - width: 100%; - height: 38px; - font-family: 'Exo 2'; - font-weight: 400; - font-size: 12px; - color: #60768b; - border-bottom: 1px solid rgba(171, 184, 196, 0.5); - padding: 0 20px; - line-height: 38px; -} - -.modal-invite-top { - width: 100%; - height: 80px; - padding: 16px 20px; - font-family: 'Lato'; - font-weight: 500; -} -.modal-invite-top__title { - font-size: 16px; - color: #333e4a; - display: block; -} -.modal-invite-top__desc { - font-style: italic; - font-size: 14px; - font-weight: 300; - color: #abb8c4; -} - -.modal-invite-list { - width: 100%; - height: 234px; - font-family: 'Lato'; - font-weight: 500; - font-size: 14px; - color: #60768b; - padding: 0; - margin-bottom: 6px; - overflow-y: auto; -} - -.modal-invite-bottom { - width: 100%; - height: 38px; - padding: 10px 20px; - text-align: right; - border-top: 1px solid rgba(171, 184, 196, 0.5); -} - -.modal-invite-bottom__button { - width: 68px; - height: 28px; - border: 1px solid #0692b0; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - font-family: 'Exo 2'; - font-weight: 400; - font-size: 12px; - color: #ffffff; - background: #32c5e6; -} -.modal-invite-bottom__button:hover, -.modal-invite-bottom__button:focus { - border: 1px solid #1a64ab; - background: #328fe6; -} diff --git a/web-sample/static/css/sample-index.css b/web-sample/static/css/sample-index.css deleted file mode 100644 index a8829376..00000000 --- a/web-sample/static/css/sample-index.css +++ /dev/null @@ -1,152 +0,0 @@ - -input, button { - outline: none; -} - -.sample-background { - background: #6e5baa; - min-width: 960px; - overflow-x: scroll; -} - -.index-section { - width: 624px; - margin: auto; - /*height: 70px;*/ -} - -.index-top { - margin-top: 80px; -} - -.index-title { - color: #fff; - font-family: 'Exo 2'; - font-weight: 200; - font-size: 26px; - margin: 0 0 0 6px; - line-height: 76px; -} - -.text-sort { - width: 310px; - padding: 0; - margin: 0; - float: left; -} - -.text-sort--right { - text-align: right; -} - -.text-sort--left { - text-align: left; -} - -.index-input { - text-align: center; -} - -.index-nickname:focus, -.index-nickname:hover, -.index-nickname:active { - border: 2px solid #32C5E6; -} - -.index-userid:focus, -.index-userid:hover, -.index-userid:active { - border: 2px solid #32C5E6; -} - - -.index-nickname, .index-userid { - padding: 0 10px 0 44px; - background: url("../img/icon-username-landing.svg") #fff no-repeat 12px; - width: 290px; - height: 48px; - border: 2px solid #fff; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; - font-family: 'Lato'; - font-weight: 400; - font-size: 16px; - color: #555555; -} -.index-userid { - margin-right: 120px; - margin-top: 40px; -} - -::-webkit-input-placeholder { /* WebKit browsers */ - font-family: 'Exo 2'; - font-weight: 400; - font-size: 16px; - color: #aaaab3 !important; -} -:-moz-placeholder { /* Mozilla Firefox 4 to 18 */ - font-family: 'Exo 2'; - font-weight: 400; - font-size: 16px; - color: #aaaab3 !important; -} -::-moz-placeholder { /* Mozilla Firefox 19+ */ - font-family: 'Exo 2'; - font-weight: 400; - font-size: 16px; - color: #aaaab3 !important; -} -:-ms-input-placeholder { /* Internet Explorer 10+ */ - font-family: 'Exo 2'; - font-weight: 400; - font-size: 16px; - color: #aaaab3 !important; -} - -.index-button { - margin: 0 0 0 6px; - width: 114px; - height: 48px; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; - border: 0; - background: #32c5e6; - font-family: 'Exo 2'; - font-weight: 700; - font-size: 16px; - color: #fff; - padding: 0; -} - -.index-button:hover, -.index-button:focus { - background: #328FE6; -} - -.index-text { - height: 100%; - margin-top: 20px; - font-family: 'Exo 2'; - font-weight: 300; - font-size: 16px; - color: #c7b0ff; - text-align: center; -} - -.index-bottom { - width: 100%; - height: 100%; - text-align: center; - margin-top: 80px; -} - -a.download-sample:link, -a.download-sample:visited { - font-family: 'Exo 2'; - font-weight: 300; - font-size: 16px; - color: #c7b0ff; - text-align: center; -} diff --git a/web-sample/static/fonts/glyphicons-halflings-regular.eot b/web-sample/static/fonts/glyphicons-halflings-regular.eot deleted file mode 100644 index b93a4953..00000000 Binary files a/web-sample/static/fonts/glyphicons-halflings-regular.eot and /dev/null differ diff --git a/web-sample/static/fonts/glyphicons-halflings-regular.svg b/web-sample/static/fonts/glyphicons-halflings-regular.svg deleted file mode 100644 index 94fb5490..00000000 --- a/web-sample/static/fonts/glyphicons-halflings-regular.svg +++ /dev/null @@ -1,288 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/web-sample/static/fonts/glyphicons-halflings-regular.ttf b/web-sample/static/fonts/glyphicons-halflings-regular.ttf deleted file mode 100644 index 1413fc60..00000000 Binary files a/web-sample/static/fonts/glyphicons-halflings-regular.ttf and /dev/null differ diff --git a/web-sample/static/fonts/glyphicons-halflings-regular.woff b/web-sample/static/fonts/glyphicons-halflings-regular.woff deleted file mode 100644 index 9e612858..00000000 Binary files a/web-sample/static/fonts/glyphicons-halflings-regular.woff and /dev/null differ diff --git a/web-sample/static/fonts/glyphicons-halflings-regular.woff2 b/web-sample/static/fonts/glyphicons-halflings-regular.woff2 deleted file mode 100644 index 64539b54..00000000 Binary files a/web-sample/static/fonts/glyphicons-halflings-regular.woff2 and /dev/null differ diff --git a/web-sample/static/img/.DS_Store b/web-sample/static/img/.DS_Store deleted file mode 100644 index 5008ddfc..00000000 Binary files a/web-sample/static/img/.DS_Store and /dev/null differ diff --git a/web-sample/static/img/btn-1on1groupchat-normal.png b/web-sample/static/img/btn-1on1groupchat-normal.png deleted file mode 100644 index cc36cd0b..00000000 Binary files a/web-sample/static/img/btn-1on1groupchat-normal.png and /dev/null differ diff --git a/web-sample/static/img/btn-1on1groupchat-normal.svg b/web-sample/static/img/btn-1on1groupchat-normal.svg deleted file mode 100644 index dc4edb0f..00000000 --- a/web-sample/static/img/btn-1on1groupchat-normal.svg +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/btn-check-click.png b/web-sample/static/img/btn-check-click.png deleted file mode 100644 index a8cf74c1..00000000 Binary files a/web-sample/static/img/btn-check-click.png and /dev/null differ diff --git a/web-sample/static/img/btn-check-click.svg b/web-sample/static/img/btn-check-click.svg deleted file mode 100644 index e5b29d37..00000000 --- a/web-sample/static/img/btn-check-click.svg +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/btn-check-normal.png b/web-sample/static/img/btn-check-normal.png deleted file mode 100644 index 4fcd95cb..00000000 Binary files a/web-sample/static/img/btn-check-normal.png and /dev/null differ diff --git a/web-sample/static/img/btn-check-normal.svg b/web-sample/static/img/btn-check-normal.svg deleted file mode 100644 index ee436c19..00000000 --- a/web-sample/static/img/btn-check-normal.svg +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/btn-check-over.png b/web-sample/static/img/btn-check-over.png deleted file mode 100644 index 5e6df29c..00000000 Binary files a/web-sample/static/img/btn-check-over.png and /dev/null differ diff --git a/web-sample/static/img/btn-check-over.svg b/web-sample/static/img/btn-check-over.svg deleted file mode 100644 index 0abdb29f..00000000 --- a/web-sample/static/img/btn-check-over.svg +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/btn-hide-normal.svg b/web-sample/static/img/btn-hide-normal.svg deleted file mode 100644 index 969b863b..00000000 --- a/web-sample/static/img/btn-hide-normal.svg +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/btn-hide-over.svg b/web-sample/static/img/btn-hide-over.svg deleted file mode 100644 index 720656a3..00000000 --- a/web-sample/static/img/btn-hide-over.svg +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/btn-invite-normal.png b/web-sample/static/img/btn-invite-normal.png deleted file mode 100644 index 3c43a580..00000000 Binary files a/web-sample/static/img/btn-invite-normal.png and /dev/null differ diff --git a/web-sample/static/img/btn-invite-normal.svg b/web-sample/static/img/btn-invite-normal.svg deleted file mode 100644 index ed109b5c..00000000 --- a/web-sample/static/img/btn-invite-normal.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/btn-invite-over.png b/web-sample/static/img/btn-invite-over.png deleted file mode 100644 index ddfee60e..00000000 Binary files a/web-sample/static/img/btn-invite-over.png and /dev/null differ diff --git a/web-sample/static/img/btn-invite-over.svg b/web-sample/static/img/btn-invite-over.svg deleted file mode 100644 index 032fefb0..00000000 --- a/web-sample/static/img/btn-invite-over.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/btn-leave-menu-click.png b/web-sample/static/img/btn-leave-menu-click.png deleted file mode 100644 index bc35fbcd..00000000 Binary files a/web-sample/static/img/btn-leave-menu-click.png and /dev/null differ diff --git a/web-sample/static/img/btn-leave-menu-click.svg b/web-sample/static/img/btn-leave-menu-click.svg deleted file mode 100644 index d904b9c5..00000000 --- a/web-sample/static/img/btn-leave-menu-click.svg +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/btn-leave-menu-over.png b/web-sample/static/img/btn-leave-menu-over.png deleted file mode 100644 index 66b0c9c0..00000000 Binary files a/web-sample/static/img/btn-leave-menu-over.png and /dev/null differ diff --git a/web-sample/static/img/btn-leave-menu-over.svg b/web-sample/static/img/btn-leave-menu-over.svg deleted file mode 100644 index f9be1f77..00000000 --- a/web-sample/static/img/btn-leave-menu-over.svg +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/btn-leave-normal.png b/web-sample/static/img/btn-leave-normal.png deleted file mode 100644 index 354bf4da..00000000 Binary files a/web-sample/static/img/btn-leave-normal.png and /dev/null differ diff --git a/web-sample/static/img/btn-leave-normal.svg b/web-sample/static/img/btn-leave-normal.svg deleted file mode 100644 index 9ebf215a..00000000 --- a/web-sample/static/img/btn-leave-normal.svg +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/btn-leave-over.png b/web-sample/static/img/btn-leave-over.png deleted file mode 100644 index 9691afff..00000000 Binary files a/web-sample/static/img/btn-leave-over.png and /dev/null differ diff --git a/web-sample/static/img/btn-leave-over.svg b/web-sample/static/img/btn-leave-over.svg deleted file mode 100644 index 0916ca9c..00000000 --- a/web-sample/static/img/btn-leave-over.svg +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/btn-memberlist-normal.png b/web-sample/static/img/btn-memberlist-normal.png deleted file mode 100644 index a8b773aa..00000000 Binary files a/web-sample/static/img/btn-memberlist-normal.png and /dev/null differ diff --git a/web-sample/static/img/btn-memberlist-normal.svg b/web-sample/static/img/btn-memberlist-normal.svg deleted file mode 100644 index 86aade9f..00000000 --- a/web-sample/static/img/btn-memberlist-normal.svg +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/btn-memberlist-over.png b/web-sample/static/img/btn-memberlist-over.png deleted file mode 100644 index cd10f98b..00000000 Binary files a/web-sample/static/img/btn-memberlist-over.png and /dev/null differ diff --git a/web-sample/static/img/btn-memberlist-over.svg b/web-sample/static/img/btn-memberlist-over.svg deleted file mode 100644 index b2282013..00000000 --- a/web-sample/static/img/btn-memberlist-over.svg +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/btn-more-normal.png b/web-sample/static/img/btn-more-normal.png deleted file mode 100644 index 22971c5b..00000000 Binary files a/web-sample/static/img/btn-more-normal.png and /dev/null differ diff --git a/web-sample/static/img/btn-more-normal.svg b/web-sample/static/img/btn-more-normal.svg deleted file mode 100644 index e9893e39..00000000 --- a/web-sample/static/img/btn-more-normal.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - diff --git a/web-sample/static/img/btn-more-over.png b/web-sample/static/img/btn-more-over.png deleted file mode 100644 index 967a5781..00000000 Binary files a/web-sample/static/img/btn-more-over.png and /dev/null differ diff --git a/web-sample/static/img/btn-more-over.svg b/web-sample/static/img/btn-more-over.svg deleted file mode 100644 index bc2fcd04..00000000 --- a/web-sample/static/img/btn-more-over.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - diff --git a/web-sample/static/img/btn-openchat-close.png b/web-sample/static/img/btn-openchat-close.png deleted file mode 100644 index b0d45f16..00000000 Binary files a/web-sample/static/img/btn-openchat-close.png and /dev/null differ diff --git a/web-sample/static/img/btn-openchat-close.svg b/web-sample/static/img/btn-openchat-close.svg deleted file mode 100644 index bd240e65..00000000 --- a/web-sample/static/img/btn-openchat-close.svg +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/btn-openchat-normal.png b/web-sample/static/img/btn-openchat-normal.png deleted file mode 100644 index 6b9b74af..00000000 Binary files a/web-sample/static/img/btn-openchat-normal.png and /dev/null differ diff --git a/web-sample/static/img/btn-openchat-normal.svg b/web-sample/static/img/btn-openchat-normal.svg deleted file mode 100644 index 29782f91..00000000 --- a/web-sample/static/img/btn-openchat-normal.svg +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/btn-upload.png b/web-sample/static/img/btn-upload.png deleted file mode 100644 index ed8015ce..00000000 Binary files a/web-sample/static/img/btn-upload.png and /dev/null differ diff --git a/web-sample/static/img/btn-upload.svg b/web-sample/static/img/btn-upload.svg deleted file mode 100644 index 2b893f9c..00000000 --- a/web-sample/static/img/btn-upload.svg +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/icon-1on1chat-title.png b/web-sample/static/img/icon-1on1chat-title.png deleted file mode 100644 index cd23bff6..00000000 Binary files a/web-sample/static/img/icon-1on1chat-title.png and /dev/null differ diff --git a/web-sample/static/img/icon-1on1chat-title.svg b/web-sample/static/img/icon-1on1chat-title.svg deleted file mode 100644 index 57809667..00000000 --- a/web-sample/static/img/icon-1on1chat-title.svg +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/icon-create-channel.svg b/web-sample/static/img/icon-create-channel.svg deleted file mode 100644 index 83634e7f..00000000 --- a/web-sample/static/img/icon-create-channel.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - diff --git a/web-sample/static/img/icon-groupchat-title.png b/web-sample/static/img/icon-groupchat-title.png deleted file mode 100644 index dc223e27..00000000 Binary files a/web-sample/static/img/icon-groupchat-title.png and /dev/null differ diff --git a/web-sample/static/img/icon-groupchat-title.svg b/web-sample/static/img/icon-groupchat-title.svg deleted file mode 100644 index 1167af55..00000000 --- a/web-sample/static/img/icon-groupchat-title.svg +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/icon-link.png b/web-sample/static/img/icon-link.png deleted file mode 100644 index 9ae4d729..00000000 Binary files a/web-sample/static/img/icon-link.png and /dev/null differ diff --git a/web-sample/static/img/icon-link.svg b/web-sample/static/img/icon-link.svg deleted file mode 100644 index 35333b30..00000000 --- a/web-sample/static/img/icon-link.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - diff --git a/web-sample/static/img/icon-list-channel.svg b/web-sample/static/img/icon-list-channel.svg deleted file mode 100644 index 3009161f..00000000 --- a/web-sample/static/img/icon-list-channel.svg +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/icon-menu-channel-off.png b/web-sample/static/img/icon-menu-channel-off.png deleted file mode 100644 index 91d7b7bd..00000000 Binary files a/web-sample/static/img/icon-menu-channel-off.png and /dev/null differ diff --git a/web-sample/static/img/icon-menu-channel-off.svg b/web-sample/static/img/icon-menu-channel-off.svg deleted file mode 100644 index f334a368..00000000 --- a/web-sample/static/img/icon-menu-channel-off.svg +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/icon-menu-channel-on.png b/web-sample/static/img/icon-menu-channel-on.png deleted file mode 100644 index 9b1243d3..00000000 Binary files a/web-sample/static/img/icon-menu-channel-on.png and /dev/null differ diff --git a/web-sample/static/img/icon-menu-channel-on.svg b/web-sample/static/img/icon-menu-channel-on.svg deleted file mode 100644 index 196589b9..00000000 --- a/web-sample/static/img/icon-menu-channel-on.svg +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/icon-menu-chat-off.png b/web-sample/static/img/icon-menu-chat-off.png deleted file mode 100644 index cc06566a..00000000 Binary files a/web-sample/static/img/icon-menu-chat-off.png and /dev/null differ diff --git a/web-sample/static/img/icon-menu-chat-off.svg b/web-sample/static/img/icon-menu-chat-off.svg deleted file mode 100644 index bdce12cd..00000000 --- a/web-sample/static/img/icon-menu-chat-off.svg +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/icon-menu-chat-on.png b/web-sample/static/img/icon-menu-chat-on.png deleted file mode 100644 index 3ac9978d..00000000 Binary files a/web-sample/static/img/icon-menu-chat-on.png and /dev/null differ diff --git a/web-sample/static/img/icon-menu-chat-on.svg b/web-sample/static/img/icon-menu-chat-on.svg deleted file mode 100644 index 58fb3543..00000000 --- a/web-sample/static/img/icon-menu-chat-on.svg +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/icon-menu-group-off.png b/web-sample/static/img/icon-menu-group-off.png deleted file mode 100644 index 72663092..00000000 Binary files a/web-sample/static/img/icon-menu-group-off.png and /dev/null differ diff --git a/web-sample/static/img/icon-menu-group-off.svg b/web-sample/static/img/icon-menu-group-off.svg deleted file mode 100644 index fb0d0970..00000000 --- a/web-sample/static/img/icon-menu-group-off.svg +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/icon-menu-group-on.png b/web-sample/static/img/icon-menu-group-on.png deleted file mode 100644 index 1310b571..00000000 Binary files a/web-sample/static/img/icon-menu-group-on.png and /dev/null differ diff --git a/web-sample/static/img/icon-menu-group-on.svg b/web-sample/static/img/icon-menu-group-on.svg deleted file mode 100644 index 1d477f91..00000000 --- a/web-sample/static/img/icon-menu-group-on.svg +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/icon-off.png b/web-sample/static/img/icon-off.png deleted file mode 100644 index 288c049f..00000000 Binary files a/web-sample/static/img/icon-off.png and /dev/null differ diff --git a/web-sample/static/img/icon-off.svg b/web-sample/static/img/icon-off.svg deleted file mode 100644 index 69851add..00000000 --- a/web-sample/static/img/icon-off.svg +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/icon-on.png b/web-sample/static/img/icon-on.png deleted file mode 100644 index 626e6c50..00000000 Binary files a/web-sample/static/img/icon-on.png and /dev/null differ diff --git a/web-sample/static/img/icon-on.svg b/web-sample/static/img/icon-on.svg deleted file mode 100644 index 6c2ebf04..00000000 --- a/web-sample/static/img/icon-on.svg +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/icon-openchat-title.png b/web-sample/static/img/icon-openchat-title.png deleted file mode 100644 index d59a4704..00000000 Binary files a/web-sample/static/img/icon-openchat-title.png and /dev/null differ diff --git a/web-sample/static/img/icon-openchat-title.svg b/web-sample/static/img/icon-openchat-title.svg deleted file mode 100644 index 11b9c401..00000000 --- a/web-sample/static/img/icon-openchat-title.svg +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/icon-search.png b/web-sample/static/img/icon-search.png deleted file mode 100644 index 30bfa3ed..00000000 Binary files a/web-sample/static/img/icon-search.png and /dev/null differ diff --git a/web-sample/static/img/icon-search.svg b/web-sample/static/img/icon-search.svg deleted file mode 100644 index 84c17681..00000000 --- a/web-sample/static/img/icon-search.svg +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/icon-time.png b/web-sample/static/img/icon-time.png deleted file mode 100644 index 14b61e0d..00000000 Binary files a/web-sample/static/img/icon-time.png and /dev/null differ diff --git a/web-sample/static/img/icon-userlist.png b/web-sample/static/img/icon-userlist.png deleted file mode 100644 index 9985591b..00000000 Binary files a/web-sample/static/img/icon-userlist.png and /dev/null differ diff --git a/web-sample/static/img/icon-userlist.svg b/web-sample/static/img/icon-userlist.svg deleted file mode 100644 index 00ed53db..00000000 --- a/web-sample/static/img/icon-userlist.svg +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/icon-username-landing.png b/web-sample/static/img/icon-username-landing.png deleted file mode 100644 index d7cd2217..00000000 Binary files a/web-sample/static/img/icon-username-landing.png and /dev/null differ diff --git a/web-sample/static/img/icon-username-landing.svg b/web-sample/static/img/icon-username-landing.svg deleted file mode 100644 index d5e6167f..00000000 --- a/web-sample/static/img/icon-username-landing.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - diff --git a/web-sample/static/img/image-landing-01.png b/web-sample/static/img/image-landing-01.png deleted file mode 100644 index 6fb7701c..00000000 Binary files a/web-sample/static/img/image-landing-01.png and /dev/null differ diff --git a/web-sample/static/img/image-landing-01.svg b/web-sample/static/img/image-landing-01.svg deleted file mode 100644 index 50582338..00000000 --- a/web-sample/static/img/image-landing-01.svg +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - - - - GROUPMESSAGE - - - - - - - - - - - - - - - - - - OPEN CHATROOM - - - - - - - - - - - - - - - - - - - - 1-ON-1MESSAGING - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/image-landing-02.png b/web-sample/static/img/image-landing-02.png deleted file mode 100644 index fad58460..00000000 Binary files a/web-sample/static/img/image-landing-02.png and /dev/null differ diff --git a/web-sample/static/img/image-landing-02.svg b/web-sample/static/img/image-landing-02.svg deleted file mode 100644 index 78c0fa68..00000000 --- a/web-sample/static/img/image-landing-02.svg +++ /dev/null @@ -1,11592 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OPEN CHAT - - 1ON1 & GROUP CHAT - - marco - : - Hola! - dosh - : - hey marco! welcome welcome - harr - y - : - Hola~ Marco! - marco - : - How are you doing guys? - harr - y - : - I'm good. How about you? - Jessi - - : - good good, we're about to go to an evening event - - - - but hopefully harry can warm you up ;) - File Uploaded: image.png - - Lobby - Game Insight - Android - News - - - - - - - - Welcome to Lobby ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - OPEN CHAT - - - - - - 1ON1 & GROUP CHAT - - - - - - - - - - - - - - - - - - Lobby - - - - - Username - Jessi - - Dosh - Herry, Marco... - Marco, Dosh... - Marco - - - - - - - - - 3 - - - 9+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - INVITE - - - - - - - - - - - - - - - CURRENT MEMBER LIST - - - - - - - - - - - - Lauren - - - Herry - - - Dosh - - - Marco - - - Regina - - - Jedk - - - Alley - - - Group Chat (3) - - - Member list shows people inside the open chat #Lobby - - - - - - - - - INVITE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - More - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Write a chat... - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/image-outerglow.png b/web-sample/static/img/image-outerglow.png deleted file mode 100644 index 104cdcf5..00000000 Binary files a/web-sample/static/img/image-outerglow.png and /dev/null differ diff --git a/web-sample/static/img/image-outerglow.svg b/web-sample/static/img/image-outerglow.svg deleted file mode 100644 index d7e2f0ba..00000000 --- a/web-sample/static/img/image-outerglow.svg +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/image-profile.png b/web-sample/static/img/image-profile.png deleted file mode 100644 index e38e98ba..00000000 Binary files a/web-sample/static/img/image-profile.png and /dev/null differ diff --git a/web-sample/static/img/image-profile.svg b/web-sample/static/img/image-profile.svg deleted file mode 100644 index 0c10b03c..00000000 --- a/web-sample/static/img/image-profile.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/img-create.png b/web-sample/static/img/img-create.png deleted file mode 100644 index 220092f3..00000000 Binary files a/web-sample/static/img/img-create.png and /dev/null differ diff --git a/web-sample/static/img/img-create.svg b/web-sample/static/img/img-create.svg deleted file mode 100644 index 6f76ab02..00000000 --- a/web-sample/static/img/img-create.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - diff --git a/web-sample/static/img/img-current.png b/web-sample/static/img/img-current.png deleted file mode 100644 index 735655c8..00000000 Binary files a/web-sample/static/img/img-current.png and /dev/null differ diff --git a/web-sample/static/img/img-current.svg b/web-sample/static/img/img-current.svg deleted file mode 100644 index 29b504b6..00000000 --- a/web-sample/static/img/img-current.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - diff --git a/web-sample/static/img/img-empty.png b/web-sample/static/img/img-empty.png deleted file mode 100644 index 567c85ae..00000000 Binary files a/web-sample/static/img/img-empty.png and /dev/null differ diff --git a/web-sample/static/img/img-empty.svg b/web-sample/static/img/img-empty.svg deleted file mode 100644 index abfe3ade..00000000 --- a/web-sample/static/img/img-empty.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - diff --git a/web-sample/static/img/img-landing-01.png b/web-sample/static/img/img-landing-01.png deleted file mode 100644 index cf1784b3..00000000 Binary files a/web-sample/static/img/img-landing-01.png and /dev/null differ diff --git a/web-sample/static/img/img-landing-02.png b/web-sample/static/img/img-landing-02.png deleted file mode 100644 index ad7acf65..00000000 Binary files a/web-sample/static/img/img-landing-02.png and /dev/null differ diff --git a/web-sample/static/img/img-leave.png b/web-sample/static/img/img-leave.png deleted file mode 100644 index f3d9687a..00000000 Binary files a/web-sample/static/img/img-leave.png and /dev/null differ diff --git a/web-sample/static/img/img-leave.svg b/web-sample/static/img/img-leave.svg deleted file mode 100644 index 1a020666..00000000 --- a/web-sample/static/img/img-leave.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/img-member.png b/web-sample/static/img/img-member.png deleted file mode 100644 index 1c05bdba..00000000 Binary files a/web-sample/static/img/img-member.png and /dev/null differ diff --git a/web-sample/static/img/img-member.svg b/web-sample/static/img/img-member.svg deleted file mode 100644 index cb28cc24..00000000 --- a/web-sample/static/img/img-member.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - diff --git a/web-sample/static/img/loading-rectagular.gif b/web-sample/static/img/loading-rectagular.gif deleted file mode 100644 index 0ac95806..00000000 Binary files a/web-sample/static/img/loading-rectagular.gif and /dev/null differ diff --git a/web-sample/static/img/logo_SendBird_reversed.svg b/web-sample/static/img/logo_SendBird_reversed.svg deleted file mode 100644 index d46b5831..00000000 --- a/web-sample/static/img/logo_SendBird_reversed.svg +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/logo_landing.png b/web-sample/static/img/logo_landing.png deleted file mode 100644 index d1d8c3b3..00000000 Binary files a/web-sample/static/img/logo_landing.png and /dev/null differ diff --git a/web-sample/static/img/logo_landing.svg b/web-sample/static/img/logo_landing.svg deleted file mode 100644 index d4dbc123..00000000 --- a/web-sample/static/img/logo_landing.svg +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/logo_main.png b/web-sample/static/img/logo_main.png deleted file mode 100644 index 2aebd1f7..00000000 Binary files a/web-sample/static/img/logo_main.png and /dev/null differ diff --git a/web-sample/static/img/logo_main.svg b/web-sample/static/img/logo_main.svg deleted file mode 100644 index 21e823d2..00000000 --- a/web-sample/static/img/logo_main.svg +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web-sample/static/img/sendbird-icon-120x120.png b/web-sample/static/img/sendbird-icon-120x120.png deleted file mode 100644 index b465f83b..00000000 Binary files a/web-sample/static/img/sendbird-icon-120x120.png and /dev/null differ diff --git a/web-sample/static/js/.DS_Store b/web-sample/static/js/.DS_Store deleted file mode 100644 index 5008ddfc..00000000 Binary files a/web-sample/static/js/.DS_Store and /dev/null differ diff --git a/web-sample/static/js/chat.js b/web-sample/static/js/chat.js deleted file mode 100644 index 89ce99d0..00000000 --- a/web-sample/static/js/chat.js +++ /dev/null @@ -1,1806 +0,0 @@ - -var appId = '9DA1B1F4-0BE6-4DA8-82C5-2E81DAB56F23'; -var currScrollHeight = 0; -var MESSAGE_TEXT_HEIGHT = 27; - -var nickname = null; -var userId = null; -var channelListPage = 0; -var currChannelUrl = null; -var currChannelInfo = null; -var leaveChannelUrl = ''; -var leaveMessagingChannelUrl = ''; -var hideChannelUrl = ''; -var userListToken = ''; -var userListNext = 0; -var targetAddGroupChannel = null; - -var isOpenChat = false; -var memberList = []; - -// 3.0.x -var currentUser; - -$('#guide_create').click(function() { - $('.modal-guide-create').hide(); -}); - -/*********************************************** - * OPEN CHAT - **********************************************/ -$('#btn_open_chat').click(function() { - popupInit(); - $('.modal-guide-create').hide(); - $('.left-nav-button-guide').hide(); - $('.modal-messaging').hide(); - $('#btn_messaging_chat').removeClass('left-nav-messaging--active'); - - if ($(this).hasClass('left-nav-open--active')) { - $('.right-section__modal-bg').hide(); - $(this).removeClass('left-nav-open--active'); - $('.modal-open-chat').hide(); - } else { - $('.right-section__modal-bg').show(); - $(this).addClass('left-nav-open--active'); - getChannelList(true); - } -}); - -$('.modal-open-chat-more').click(function() { - getChannelList(false); -}); - -// Create OpenChannel -$('#btn_create_open_channel').click(function(){ - modalInput("Create Open Channel", "", function(channelName){ - sb.OpenChannel.createChannel(channelName, '', '', function(channel, error){ - joinChannel(channel.url); - }); - }); -}); - -$(document).on('click', '.chat-canvas__list-name', function(e){ - var userId = $(this).data('userid'); - if (isCurrentUser(userId)) { - console.log('can not block, current user'); - return; - } - - modalConfirm('Are you Sure?', 'Do you want to block this user?', function(){ - sb.blockUserWithUserId(userId, function(response, error){ - console.log(response, error); - }); - }); -}); - - -$(document).on('click', '.chat-canvas__list-text', function(e){ - var userId = $(this).prev().prev().data('userid'); - var messageId = $(this).data('messageid'); - var channelUrl = currChannelInfo.url; - var messageObject = $(this); - - modalConfirm('Are you Sure?', 'Do you want to delete message?', function(){ - currChannelInfo.deleteMessage(channelMessageList[channelUrl][messageId]['message'], function(response, error){ - if (!error) { - delete(channelMessageList[channelUrl][messageId]); - messageObject.parent().remove(); - } - }); - }); -}); - -function debounce(func, wait, immediate) { - var timeout; - return function() { - var context = this, args = arguments; - var later = function() { - timeout = null; - if (!immediate) func.apply(context, args); - }; - var callNow = immediate && !timeout; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - if (callNow) func.apply(context, args); - }; -}; - - -function modalConfirm(title, desc, submit, close){ - - console.log("modalConfirmmodalConfirmmodalConfirmmodalConfirmmodalConfirmmodalConfirm"); - - $('.modal-confirm-title').html(title); - $('.modal-confirm-desc').html(desc); - - $('.modal-confirm-submit').unbind('click'); - $('.modal-confirm-close').unbind('click'); - - $('.modal-confirm-close').click(function(){ - if (close) { - close_modal = debounce(close, 1000, true); - close_modal(); - } - $('.modal-confirm').hide(); - $('.modal-confirm-close').unbind('click'); - }); - - $('.modal-confirm-submit').click(function(){ - if (submit) { - submit_modal = debounce(submit, 1000, true); - submit_modal(); - } - $('.modal-confirm').hide(); - $('.modal-confirm-submit').unbind('click'); - }); - - $('.modal-confirm').show(); -} - -function modalInput(title, desc, submit, close){ - $('.modal-input-title').html(title); - $('.modal-input-desc').html(desc); - - // $('.modal-confirm-submit').unbind('click'); - // $('.modal-confirm-close').unbind('click'); - - $('.modal-input-box-elem').keydown(function(e){ - var keyCode = e.which; - switch(keyCode) { - case 13: // enter - if (submit) { - submit($('.modal-input-box-elem').val()); - } - $('.modal-input').hide(); - $('.modal-input-close').unbind('click'); - $('.modal-input-box-elem').unbind('keydown'); - break; - case 27: // esc - if (close) { - close(); - } - $('.modal-input').hide(); - $('.modal-input-close').unbind('click'); - $('.modal-input-box-elem').unbind('keydown'); - break; - } - }); - - $('.modal-input-close').click(function(){ - if (close) { - close(); - } - $('.modal-input').hide(); - $('.modal-input-close').unbind('click'); - }); - - $('.modal-input-submit').click(function(){ - if (submit) { - submit($('.modal-input-box-elem').val()); - } - $('.modal-input').hide(); - $('.modal-input-submit').unbind('click'); - }); - - $('.modal-input').show(0, function(){ - $('.modal-input-box-elem').focus(); - }); -} - -function showChatUI(){ - $('.chat').show(); - if(typeof moxie !== 'undefined' && moxie){ - console.log("existing"); - var fileInput = new moxie.file.FileInput({ - browse_button: 'chat_file_input2', // or document.getElementById('file-picker') - accept: [ - {title: "Images", extensions: "jpg,gif,png"} // accept only images - ] - }); - fileInput.onchange = function(e) { - // do something to files array - target_file = e.target.files[0]; - reader = new moxie.file.FileReader(); - reader.onload = function(e){ - var send_file = {'name':target_file.name,'type':target_file.type,'base64':e.target.result.split(',')[1]}; - currChannelInfo.sendFileMessage(send_file, SendMessageHandler); - } - reader.readAsDataURL(target_file); - }; - fileInput.init(); // initialize - } -} - - -function getChannelList(isFirstPage) { - if(isFirstPage) { - $('.modal-open-chat-list').html(''); - OpenChannelListQuery = sb.OpenChannel.createOpenChannelListQuery(); - } - - if (OpenChannelListQuery.hasNext) { - OpenChannelListQuery.next(function(channels, error){ - if (error) { - return; - } - - $('.modal-open-chat-list').append(createChannelList(channels)); - channelListPage = channels['page']; - if (channels['next'] != 0) { - $('.modal-open-chat-more').show(); - } else { - $('.modal-open-chat-more').hide(); - } - $('.modal-open-chat').show(); - }); - } -} - -function createChannelList(channels) { - var channelListHtml = ''; - - for (var i in channels) { - var channel = channels[i]; - var item = ''; - item = item.replace(/%channelUrl%/, channel.url).replace(/%channelName%/, channel.name); - item = item.replace(/%channelImage%/, ' '); - - channelListHtml += item; - } - return channelListHtml; -} - -function joinChannel(channelUrl) { - if (channelUrl == currChannelUrl) { - navInit(); - popupInit(); - return false; - } - - PreviousMessageListQuery = null; - sb.OpenChannel.getChannel(channelUrl, function(channel, error){ - if (error) { - return; - } - - channel.enter(function(response, error){ - if (error) { - if (error.code == 900100) { - alert('Oops...You got banned out from this channel.'); - } - return; - } - - $('.chat-top__button-hide').hide(); - - currChannelInfo = channel; - currChannelUrl = channelUrl; - - $('.chat-empty').hide(); - initChatTitle(currChannelInfo.name, 0); - - $('.chat-canvas').html(''); - $('.chat-input-text__field').val(''); - showChatUI(); - - navInit(); - popupInit(); - - isOpenChat = true; - loadMoreChatMessage(scrollPositionBottom); - setWelcomeMessage(currChannelInfo.name); - addChannel(); - $('.chat-input-text__field').attr('disabled', false); - - }); - }); -} - -function addChannel() { - if ($('.left-nav-channel-open').length == 0) { - $('.left-nav-channel-empty').hide(); - } - - $.each($('.left-nav-channel'), function(index, channel) { - $(channel).removeClass('left-nav-channel-open--active'); - $(channel).removeClass('left-nav-channel-messaging--active'); - $(channel).removeClass('left-nav-channel-group--active'); - }); - - var addFlag = true; - $.each($('.left-nav-channel-open'), function(index, channel) { - if (currChannelUrl == $(channel).data('channel-url')) { - $(channel).addClass('left-nav-channel-open--active'); - addFlag = false; - } - }); - - if(addFlag) { - $('#open_channel_list').append( - '
' + - (currChannelInfo.name.length > 12 ? currChannelInfo.name.substring(0, 12) + '...' : currChannelInfo["name"]) + - '
' - ); - } - - $('.modal-guide-create').hide(); - $('.left-nav-button-guide').hide(); -} - -function leaveChannel(channel, obj) { - popupInit(); - - leaveChannelUrl = channel['channel_url']; - - if($('.chat-top__button-invite').is(':visible')) { - $('.modal-leave-channel-desc').html('Do you want to leave this messaging channel?'); - } else { - $('.modal-leave-channel-desc').html('Do you want to leave this channel?'); - } - - $('.modal-leave-channel').show(); - return false; -} - -$('.chat-top__button-leave').click(function() { - if($('.chat-top__button-invite').is(':visible')) { - endMessaging(currChannelInfo, $(this)) - } else { - leaveChannel(currChannelInfo, $(this)); - } -}); - -$('.chat-top__button-hide').click(function() { - if (currChannelInfo.isOpenChannel()) { - return; - } - - hideChannel(currChannelInfo); -}); - -$('.chat-top__button-member').click(function() { - if ($('.modal-member').is(":visible")) { - $(this).removeClass('chat-top__button-member--active'); - $('.modal-member').hide(); - } else { - popupInit(); - $(this).addClass('chat-top__button-member--active'); - getMemberList(currChannelInfo); - $('.modal-member').show(); - } -}); - -$('.chat-top__button-invite').click(function() { - if ($('.modal-invite').is(":visible")) { - $(this).removeClass('chat-top__button-invite--active'); - $('.modal-invite').hide(); - } else { - popupInit(); - $(this).addClass('chat-top__button-invite--active'); - getUserList(); - $('.modal-invite').show(); - } -}); - -function getMemberList(channel) { - if (channel.isOpenChannel()) { - OpenChannelParticipantListQuery = channel.createParticipantListQuery(channel); - OpenChannelParticipantListQuery.next(function (members, error) { - if (error) { - return; - } - - $('.modal-member-list').html(''); - var memberListHtml = ''; - members.forEach(function (member) { - memberListHtml += '' + - ''; - }); - $('.modal-member-list').html(memberListHtml); - }); - } - - if (channel.isGroupChannel()) { - var members = channel.members; - $('.modal-member-list').html(''); - - var memberListHtml = ''; - members.forEach(function (member) { - if (member.connectionStatus == 'online') { - var isOnline = 'online'; - var dateTimeString = ''; - } else { - var isOnline = ''; - var dateTime = new Date(member.lastSeenAt); - var dateTimeString = (dateTime.getMonth()+1) + '/' + dateTime.getDate() + ' ' + dateTime.getHours() + ':' + dateTime.getMinutes(); - } - - - memberListHtml += '' + - ''; - }); - $('.modal-member-list').html(memberListHtml); - } -} - -$('.modal-leave-channel-close').click(function() { - $('.modal-leave-channel').hide(); - leaveChannelUrl = ''; - return false; -}); - -$('.modal-leave-channel-submit').click(function() { - $('#open_channel_list').removeClass('chat-top__button-leave--active'); - - leaveCurrChannel(); -}); - -$('.modal-hide-channel-close').click(function() { - $('.modal-hide-channel').hide(); - leaveChannelUrl = ''; - return false; -}); - -$('.modal-hide-channel-submit').click(function() { - // $('#open_channel_list').removeClass('chat-top__button-leave--active'); - // leaveCurrChannel(); - hideCurrChannel(); -}); -/*********************************************** - * // END OPEN CHAT - **********************************************/ - - -/*********************************************** - * MESSAGING - **********************************************/ -$('#btn_messaging_chat').click(function() { - popupInit(); - $('.modal-guide-create').hide(); - $('.left-nav-button-guide').hide(); - $('.modal-open-chat').hide(); - $('#btn_open_chat').removeClass('left-nav-open--active'); - - if ($(this).hasClass('left-nav-messaging--active')) { - $('.right-section__modal-bg').hide(); - $(this).removeClass('left-nav-messaging--active'); - $('.modal-messaging').hide(); - } else { - $('.right-section__modal-bg').show(); - $(this).addClass('left-nav-messaging--active'); - userListToken = ''; - userListNext = 0; - $('.modal-messaging-list').html(''); - getUserList(true); - $('.modal-messaging').show(); - } -}); - -function getUserList(isFirstPage) { - if (isFirstPage) { - $('.modal-messaging-list').html(''); - UserListQuery = sb.createUserListQuery(); - } - - if (UserListQuery.hasNext) { - UserListQuery.next(function(userList, error){ - if (error) { - return; - } - - var users = userList; - $('.modal-messaging-more').remove(); - $.each(users, function(index, user) { - UserList[user.userId] = user; - if (!isCurrentUser(user.userId)) { - $('.modal-messaging-list').append( - '' - ); - } - }); - - if (UserListQuery.hasNext) { - $('.modal-messaging-list').append( - '' - ); - } else { - $('.modal-messaging-more').remove(); - } - }); - } - -} - -function userListLoadMore() { - getUserList(false); -} - -function userClick(obj) { - var el = obj.find('div'); - if (el.hasClass('modal-messaging-list__icon--select')) { - el.removeClass('modal-messaging-list__icon--select'); - } else { - el.addClass('modal-messaging-list__icon--select'); - } - - var selectCount = $('.modal-messaging-list__icon--select').length; - if (selectCount > 1) { - $('.modal-messaging-top__title').html('Group Chat ({})'.format(selectCount)); - } else { - $('.modal-messaging-top__title').html('Group Channel'); - } -} - -function startMessaging() { - if ($('.modal-messaging-list__icon--select').length == 0) { - alert('Please select user'); - return false; - } - - var startMessagingProcess = function(){ - console.log("startMessagingProcessstartMessagingProcessstartMessagingProcessstartMessagingProcessstartMessagingProcess"); - var users = []; - $.each($('.modal-messaging-list__icon--select'), function(index, user) { - users.push(UserList[$(user).data("guest-id")]); - }); - - PreviousMessageListQuery = null; - sb.GroupChannel.createChannel(users, isDistinct, 'test_name', '', '', function(channel, error){ - if (error) { - return; - } - - currChannelInfo = channel; - currChannelUrl = channel.url; - - var members = channel.members; - var channelTitle = ''; - - $.each(members, function(index, member) { - if (!isCurrentUser(member.userId)) { - channelTitle += member.nickname + ', '; - } - }); - - channelTitle = channelTitle.slice(0,-2); - var channelMemberList = channelTitle; - if (channelTitle.length > 20) { - channelTitle = channelTitle.substring(0, 20); - channelTitle += '...' - } - var titleType = 1; - var isGroup = true; - if(members.length > 2) { - channelTitle += '({})'.format(members.length); - titleType = 2; - } - - $('.chat-empty').hide(); - initChatTitle(channelTitle, titleType); - $('.chat-canvas').html(''); - $('.chat-input-text__field').val(''); - showChatUI(); - - navInit(); - popupInit(); - makeMemberList(members); - - isOpenChat = false; - loadMoreChatMessage(scrollPositionBottom); - setWelcomeMessage('Messaging Channel'); - addGroupChannel(true, channelMemberList, currChannelInfo); - $('.chat-input-text__field').attr('disabled', false); - }); - }; - - var isDistinct; - modalConfirm('Create Channel', 'Do you want to create distinct channel?', function(){ - isDistinct = true; - startMessagingProcess(); - }, function(){ - isDistinct = false; - startMessagingProcess(); - }); - - return; -} - -function deleteChannel(channel) { - var channelUrl = channel.url; - - if (channel.isGroupChannel()) { - $('.left-nav-channel-group[data-channel-url='+channelUrl+']').remove(); - delete(groupChannelLastMessageList[channelUrl]); - } - - if (channel.isOpenChannel()) { - $('.left-nav-channel-open[data-channel-url='+channelUrl+']').remove(); - } - - try { - delete(channelMessageList[channelUrl]); - } catch (e) { - // pass - } - - if (channel == currChannelInfo) { - leaveCurrChannel(); - } -} - -function hideCurrChannel(){ - console.log('hideCurrChannel called'); - if (currChannelInfo.isGroupChannel()) { - currChannelInfo.hide(function(response, error){ - if (error) { - return; - } - - $('.chat-canvas').html(''); - $('.chat-input-text__field').val(''); - $('.chat').hide(); - initChatTitle('', -1); - $('.chat-empty').show(); - - $('.left-nav-channel-messaging--active').remove(); - $('.left-nav-channel-group--active').remove(); - - $('.modal-hide-channel').hide(); - channelListPage = 0; - currChannelUrl = null; - currChannelInfo = null; - leaveMessagingChannelUrl = ''; - - $('.chat-input-text__field').attr('disabled', true); - }); - } -} - -function leaveCurrChannel(){ - console.log('leaveCurrChannel called'); - if (currChannelInfo.isOpenChannel()) { - currChannelInfo.exit(function(response, error){ - if (error) { - return; - } - $('.chat-canvas').html(''); - $('.chat-input-text__field').val(''); - $('.chat').hide(); - initChatTitle('', -1); - $('.chat-empty').show(); - - $('.left-nav-channel-open--active').remove(); - - if ($('.left-nav-channel-open').length == 0) { - $('.left-nav-channel-empty').show(); - } - - $('.modal-leave-channel').hide(); - channelListPage = 0; - currChannelUrl = null; - currChannelInfo = null; - leaveChannelUrl = ''; - - $('.chat-input-text__field').attr('disabled', true); - }); - } else if (currChannelInfo.isGroupChannel()) { - currChannelInfo.leave(function(response, error){ - if (error) { - return; - } - - $('.chat-canvas').html(''); - $('.chat-input-text__field').val(''); - $('.chat').hide(); - initChatTitle('', -1); - $('.chat-empty').show(); - - $('.left-nav-channel-messaging--active').remove(); - $('.left-nav-channel-group--active').remove(); - - $('.modal-leave-channel').hide(); - channelListPage = 0; - currChannelUrl = null; - currChannelInfo = null; - leaveMessagingChannelUrl = ''; - - $('.chat-input-text__field').attr('disabled', true); - }); - } -} - - -function moveToTopGroupChat(channelUrl) { - $('.left-nav-channel-group[data-channel-url='+channelUrl+']').prependTo('#messaging_channel_list'); -} - -function updateGroupChannelLastMessage(message){ - var lastMessage = ''; - var lastMessageDateString = ''; - if (message) { - lastMessage = message.message; - var calcSeconds = (new Date().getTime() - message.createdAt)/1000; - var parsedValue; - - if (calcSeconds < 60) { - parsedValue = parseInt(calcSeconds); - if (parsedValue == 1) { - lastMessageDateString = parsedValue + ' sec ago'; - } else { - lastMessageDateString = parsedValue + ' secs ago'; - } - } else if (calcSeconds / 60 < 60) { - parsedValue = parseInt(calcSeconds/60); - if (parsedValue == 1) { - lastMessageDateString = parsedValue + ' min ago'; - } else { - lastMessageDateString = parsedValue + ' mins ago'; - } - } else if (calcSeconds / (60*60) < 24) { - parsedValue = parseInt(calcSeconds / (60*60)); - if (parsedValue == 1) { - lastMessageDateString = parsedValue + ' hour ago'; - } else { - lastMessageDateString = parsedValue + ' hours ago'; - } - } else { - parsedValue = parseInt(calcSeconds/(60*60*24)); - if (parsedValue == 1) { - lastMessageDateString = parsedValue + ' day ago'; - } else { - lastMessageDateString = parsedValue + ' days ago'; - } - } - - if (lastMessageDateString) { - lastMessageDateString = '
' + lastMessageDateString + '
'; - } - - $('.left-nav-channel-group[data-channel-url='+message.channelUrl+'] .left-nav-channel-lastmessage').html(lastMessage); - $('.left-nav-channel-group[data-channel-url='+message.channelUrl+'] .left-nav-channel-lastmessagetime').html(lastMessageDateString); - } -} - -function updateGroupChannelListAll(){ - for (var i in groupChannelLastMessageList) { - var message = groupChannelLastMessageList[i]; - updateGroupChannelLastMessage(message); - } -} - - -function addGroupChannel(isGroup, channelMemberList, targetChannel) { - if (isGroup) { - groupChannelLastMessageList[targetChannel.url] = targetChannel.lastMessage; - } - - $.each($('.left-nav-channel'), function(index, channel) { - $(channel).removeClass('left-nav-channel-open--active'); - $(channel).removeClass('left-nav-channel-messaging--active'); - $(channel).removeClass('left-nav-channel-group--active'); - }); - - var addFlag = true; - $.each($('.left-nav-channel-messaging'), function(index, channel) { - if (currChannelUrl == $(channel).data('channel-url')) { - $(channel).addClass('left-nav-channel-messaging--active'); - $(channel).find('div[class="left-nav-channel__unread"]').remove(); - addFlag = false; - } - }); - $.each($('.left-nav-channel-group'), function(index, channel) { - if (currChannelUrl == $(channel).data('channel-url')) { - $(channel).addClass('left-nav-channel-group--active'); - $(channel).find('div[class="left-nav-channel__unread"]').remove(); - addFlag = false; - } - }); - - if (channelMemberList.length > 9) { - channelMemberList = channelMemberList.substring(0, 9) + '...'; - } - - targetAddGroupChannel = targetChannel; - if (addFlag && !isGroup) { - $('#messaging_channel_list').append( - '
' + - channelMemberList + - '
' - ); - - groupChannelListMembersAndProfileImageUpdate(targetChannel); - } else if (addFlag && isGroup) { - $('#messaging_channel_list').append( - '
' + - '
' + channelMemberList +'
' + - '
' + - '
' + - '
' - ); - targetAddGroupChannel = null; - groupChannelListMembersAndProfileImageUpdate(targetChannel); - } - - $('.modal-guide-create').hide(); - $('.left-nav-button-guide').hide(); -} - -function groupChannelListMembersAndProfileImageUpdate(targetChannel){ - // select profileImage - var members = targetChannel.members; - // console.log(members); - - var membersProfileImageUrl = []; - var membersNickname = ''; - for (var i in members){ - var member = members[i]; - if (sb.currentUser.userId != member.userId) { - membersProfileImageUrl.push(member.profileUrl); - } - - membersNickname += member.nickname + ', '; - } - membersNickname = membersNickname.substring(0, membersNickname.length - 2); - - if (membersNickname.length > 22) { - membersNickname = membersNickname.substring(0, 22) + '...'; - } - - // console.log(membersProfileImageUrl); - var selectSequence = parseInt(Math.random() * membersProfileImageUrl.length); - // console.log(selectSequence); - var selectedProfileImageUrl = membersProfileImageUrl[selectSequence]; - // console.log(selectedProfileImageUrl); - - var targetElem = $('.left-nav-channel-group[data-channel-url='+targetChannel.url+']'); - // $('.left-nav-channel-group[data-channel-url='+targetChannel.url+']') - - targetElem.css('background-image', 'url('+selectedProfileImageUrl+')'); - - // member nickname update - targetElem.find('.left-nav-channel-members').html(membersNickname); - -} - -function joinGroupChannel(channelUrl, callback) { - // console.log('joinGroupChannel:', channelUrl); - - if (channelUrl == currChannelUrl) { - navInit(); - popupInit(); - $.each($('.left-nav-channel'), function(index, channel) { - if ($(channel).data('channel-url') == channelUrl) { - $(channel).find('div[class="left-nav-channel__unread"]').remove(); - } - }); - return false; - } - - PreviousMessageListQuery = null; - sb.GroupChannel.getChannel(channelUrl, function(channel, error){ - if (error) { - console.error(error); - return; - } - - channel.markAsRead(); - - currChannelInfo = channel; - currChannelUrl = channelUrl; - - var members = channel.members; - var channelTitle = ''; - - channel.refresh(function(){ - // TODO - }); - - $.each(members, function(index, member) { - if (!isCurrentUser(member.userId)) { - channelTitle += member.nickname + ', '; - } - }); - - channelTitle = channelTitle.slice(0,-2); - var channelMemberList = channelTitle; - if (channelTitle.length > 20) { - channelTitle = channelTitle.substring(0, 20); - channelTitle += '...'; - } - var titleType = 1; - var isGroup = false; - if (members.length > 2) { - channelTitle += '({})'.format(members.length); - titleType = 2; - isGroup = true; - } - - $('.chat-empty').hide(); - initChatTitle(channelTitle, titleType); - $('.chat-canvas').html(''); - $('.chat-input-text__field').val(''); - showChatUI(); - - navInit(); - popupInit(); - makeMemberList(members); - - isOpenChat = false; - loadMoreChatMessage(scrollPositionBottom); - setWelcomeMessage('Group Channel'); - addGroupChannel(isGroup, channelMemberList, currChannelInfo); - $('.chat-input-text__field').attr('disabled', false); - - $('.chat-top__button-hide').show(); - if (callback) { - callback(); - } - }); - - return; - -} - -function endMessaging(channel, obj) { - popupInit(); - leaveMessagingChannelUrl = channel.url; - $('.modal-leave-channel-desc').html('Do you want to leave this messaging channel?'); - $('.modal-leave-channel').show(); - return false; -} - -function hideChannel(channel) { - popupInit(); - hideChannelUrl = channel.url; - $('.modal-hide-channel-desc').html('Do you want to hide this channel?'); - $('.modal-hide-channel').show(); - return false; -} - -function inviteMember() { - if ($('.modal-messaging-list__icon--select').length == 0) { - alert('Please select user'); - return false; - } - - var userIds = []; - $.each($('.modal-messaging-list__icon--select'), function(index, user) { - if ($(user).data("guest-id")) { - userIds.push($(user).data("guest-id")); - } - }); - - currChannelInfo.inviteWithUserIds(userIds, function(response, error) { - if (error) { - return; - } - - popupInit(); - }); - -} - -function getGroupChannelList() { - GroupChannelListQuery.next(function(channels, error){ - if (error) { - return; - } - - channels.forEach(function(channel){ - var channelMemberList = ''; - var members = channel.members; - - members.forEach(function(member){ - if (currentUser.userId != member.userId) { - channelMemberList += member.nickname + ', '; - } - }); - - channelMemberList = channelMemberList.slice(0, -2); - addGroupChannel(true, channelMemberList, channel); - - $.each($('.left-nav-channel'), function(index, item) { - $(item).removeClass('left-nav-channel-messaging--active'); - $(item).removeClass('left-nav-channel-group--active'); - }); - - var targetUrl = channel.url; - var unread = channel.unreadMessageCount > 9 ? '9+' : channel.unreadMessageCount; - if (unread != 0) { - $.each($('.left-nav-channel'), function(index, item) { - if ($(item).data("channel-url") == targetUrl) { - addUnreadCount(item, unread, targetUrl); - } - }); - } - }); - - }); - -} - -function makeMemberList(members) { - var item = {}; - //Clear memberList before updating it - memberList = []; - $.each(members, function(index, member) { - item = {}; - if (!isCurrentUser(member['user_id'])) { - item["user_id"] = member["user_id"]; - item["name"] = member["name"]; - memberList.push(item); - } - }); -} -/*********************************************** - * // END MESSAGING - **********************************************/ - - -/*********************************************** - * SendBird Settings - **********************************************/ -var sb; - -var GroupChannelListQuery; -var OpenChannelListQuery; -var OpenChannelParticipantListQuery; - -var UserListQuery; -var SendMessageHandler; - -var UserList = {}; -var isInit = false; - -var channelMessageList = {}; -var groupChannelLastMessageList = {}; - -function startSendBird(userId, nickName) { - sb = new SendBird({ - appId: appId - }); - - sb.connect(userId, function(user, error){ - if (error) { - return; - } else { - initPage(user); - } - }); - - var initPage = function(user){ - isInit = true; - $('.init-check').hide(); - - currentUser = user; - sb.updateCurrentUserInfo(nickName, '', function(response, error) { - // console.log(response, error); - }); - - GroupChannelListQuery = sb.GroupChannel.createMyGroupChannelListQuery(); - OpenChannelListQuery = sb.OpenChannel.createOpenChannelListQuery(); - UserListQuery = sb.createUserListQuery(); - - GroupChannelListQuery.limit = 100; - GroupChannelListQuery.includeEmpty = true; - OpenChannelListQuery.limit = 100; - - UserListQuery.limit = 100; - - getGroupChannelList(); - - setTimeout(function(){ - updateGroupChannelListAll(); - setInterval(function(){ - updateGroupChannelListAll(); - }, 1000); - }, 500); - }; - - var ConnectionHandler = new sb.ConnectionHandler(); - ConnectionHandler.onReconnectStarted = function(id) { - console.log('onReconnectStarted'); - }; - - ConnectionHandler.onReconnectSucceeded = function(id) { - console.log('onReconnectSucceeded'); - if (!isInit) { - initPage(); - } - - // OpenChannel list reset - if ($('.right-section__modal-bg').is(':visible')) { - var withoutCache = true; - getChannelList(withoutCache); - } - - // GroupChannel list reset - GroupChannelListQuery = sb.GroupChannel.createMyGroupChannelListQuery(); - $('#messaging_channel_list').html(''); - getGroupChannelList(); - - setTimeout(function(){ - updateGroupChannelListAll(); - setInterval(function(){ - updateGroupChannelListAll(); - }, 1000); - }, 500); - }; - - ConnectionHandler.onReconnectFailed = function(id) { - console.log('onReconnectFailed'); - }; - sb.addConnectionHandler('uniqueID', ConnectionHandler); - - var ChannelHandler = new sb.ChannelHandler(); - ChannelHandler.onMessageReceived = function(channel, message){ - var isCurrentChannel = false; - - if (currChannelInfo == channel) { - isCurrentChannel = true; - } - - channel.refresh(function(){ - }); - - // update last message - if (channel.isGroupChannel()) { - groupChannelLastMessageList[channel.url] = message; - updateGroupChannelLastMessage(message); - moveToTopGroupChat(channel.url); - } - - if (isCurrentChannel && channel.isGroupChannel()) { - channel.markAsRead(); - unreadCountUpdate(channel); - } - - if (!document.hasFocus()) { - notifyMessage(channel, message.message); - } - - if (message.isUserMessage() && isCurrentChannel) { - setChatMessage(message); - } - - if (message.isFileMessage() && isCurrentChannel) { - if (message.type.match(/^image\/.+$/)) { - setImageMessage(message); - } else { - setFileMessage(message); - } - } - - if (message.isAdminMessage() && isCurrentChannel) { - setBroadcastMessage(message); - } - }; - - SendMessageHandler = function(message, error) { - if (error) { - if (error.code == 900050) { - setSysMessage({'message': 'This channel is freeze.'}); - return; - } else if(error.code == 900041) { - setSysMessage({'message': 'You are muted.'}); - return; - } - } - - // update last message - if (groupChannelLastMessageList.hasOwnProperty(message.channelUrl)) { - groupChannelLastMessageList[message.channelUrl] = message; - updateGroupChannelLastMessage(message); - } - - if (message.isUserMessage()) { - setChatMessage(message); - } - - if (message.isFileMessage()) { - $('.chat-input-file').removeClass('file-upload'); - $('#chat_file_input').val(''); - - if (message.type.match(/^image\/.+$/)) { - setImageMessage(message); - } else { - setFileMessage(message); - } - } - }; - - ChannelHandler.onMessageDeleted = function (channel, messageId) { - console.log('ChannelHandler.onMessageDeleted: ', channel, messageId); - }; - - ChannelHandler.onReadReceiptUpdated = function (channel) { - console.log('ChannelHandler.onReadReceiptUpdated: ', channel); - updateChannelMessageCacheAll(channel); - }; - - ChannelHandler.onTypingStatusUpdated = function (channel) { - console.log('ChannelHandler.onTypingStatusUpdated: ', channel); - - if (channel == currChannelInfo) { - showTypingUser(channel); - } - }; - - ChannelHandler.onUserJoined = function (channel, user) { - console.log('ChannelHandler.onUserJoined: ', channel, user); - }; - - ChannelHandler.onUserLeft = function (channel, user) { - console.log('ChannelHandler.onUserLeft: ', channel, user); - setSysMessage({'message': '"' + user.nickname + '" user is left.'}); - - if (channel.isGroupChannel()){ - groupChannelListMembersAndProfileImageUpdate(channel); - } - }; - - ChannelHandler.onUserEntered = function (channel, user) { - console.log('ChannelHandler.onUserEntered: ', channel, user); - }; - - ChannelHandler.onUserExited = function (channel, user) { - console.log('ChannelHandler.onUserExited: ', channel, user); - }; - - ChannelHandler.onUserMuted = function (channel, user) { - console.log('ChannelHandler.onUserMuted: ', channel, user); - }; - - ChannelHandler.onUserUnmuted = function (channel, user) { - console.log('ChannelHandler.onUserUnmuted: ', channel, user); - }; - - ChannelHandler.onUserBanned = function (channel, user) { - console.log('ChannelHandler.onUserBanned: ', channel, user); - if (isCurrentUser(user.userId)) { - alert('Oops...You got banned out from this channel.'); - navInit(); - popupInit(); - } else { - setSysMessage({'message': '"' + user.nickname + '" user is banned.'}); - } - }; - - ChannelHandler.onUserUnbanned = function (channel, user) { - console.log('ChannelHandler.onUserUnbanned: ', channel, user); - setSysMessage({'message': '"' + user.nickname + '" user is unbanned.'}); - }; - - ChannelHandler.onChannelFrozen = function (channel) { - console.log('ChannelHandler.onChannelFrozen: ', channel); - }; - - ChannelHandler.onChannelUnfrozen = function (channel) { - console.log('ChannelHandler.onChannelUnfrozen: ', channel); - }; - - ChannelHandler.onChannelChanged = function (channel) { - console.log('ChannelHandler.onChannelChanged: ', channel); - if (channel.isGroupChannel()){ - groupChannelListMembersAndProfileImageUpdate(channel); - } - }; - - ChannelHandler.onChannelDeleted = function (channel) { - console.log('ChannelHandler.onChannelDeleted: ', channel); - deleteChannel(channel); - }; - - sb.addChannelHandler('channel', ChannelHandler); -} - -// var startTyping = function(user){ -// typingUser[user.userId] = user.nickname; -// showTypingUser(); -// }; -// -// var endTyping = function(user){ -// delete(typingUser[user.userId]); -// showTypingUser(); -// }; - -var showTypingUser = function(channel){ - if (!channel.isGroupChannel()) { - return; - } - - if (!channel.isTyping()) { - $('.chat-input-typing').hide(); - $('.chat-input-typing').html(''); - return; - } - - var typingUser = channel.getTypingMembers(); - - var nicknames = ''; - for (var i in typingUser) { - var nickname = typingUser[i].nickname; - nicknames += nickname + ', '; - } - if (nicknames.length > 2) { - nicknames = nicknames.substring(0, nicknames.length-2); - $('.chat-input-typing').html('{} typing...'.format(nicknames)); - $('.chat-input-typing').show(); - } else { - $('.chat-input-typing').hide(); - $('.chat-input-typing').html(''); - } -}; - - -/*********************************************** - * // END SendBird Settings - **********************************************/ - - -/*********************************************** - * Common Function - **********************************************/ -function initChatTitle(title, index) { - $('.chat-top__title').html(title); - $('.chat-top__title').show(); - $('.chat-top-button').show(); - $('.chat-top__button-invite').hide(); - $('.chat-top__title').removeClass('chat-top__title--messaging'); - $('.chat-top__title').removeClass('chat-top__title--group'); - if (index == -1) { - $('.chat-top__title').hide(); - $('.chat-top-button').hide(); - } else if (index == 0) { - $('.chat-top__button-member').removeClass('chat-top__button-member__all'); - $('.chat-top__button-member').addClass('chat-top__button-member__right'); - } else { - if (index == 1) { - $('.chat-top__title').addClass('chat-top__title--messaging'); - } else { - $('.chat-top__title').addClass('chat-top__title--group'); - } - $('.chat-top__button-member').removeClass('chat-top__button-member__right'); - $('.chat-top__button-member').addClass('chat-top__button-member__all'); - $('.chat-top__button-invite').show(); - } -} - -var scrollPositionBottom = function() { - var scrollHeight = $('.chat-canvas')[0].scrollHeight; - $('.chat-canvas')[0].scrollTop = scrollHeight; - currScrollHeight = scrollHeight; -}; - -function afterImageLoad(obj) { - $('.chat-canvas')[0].scrollTop = $('.chat-canvas')[0].scrollTop + obj.height + $('.chat-canvas__list').height(); -} - -function setChatMessage(message) { - $('.chat-canvas').append(messageList(message)); - - updateChannelMessageCache(currChannelInfo, message); - scrollPositionBottom(); -} - -var PreviousMessageListQuery = null; -function loadMoreChatMessage(func) { - if (!PreviousMessageListQuery) { - PreviousMessageListQuery = currChannelInfo.createPreviousMessageListQuery(); - } - - PreviousMessageListQuery.load(30, false, function(messages, error){ - if (error) { - return; - } - - var moreMessage = messages; - var msgList = ''; - messages.forEach(function(message){ - if(message.isUserMessage()){ - msgList += messageList(message); - } else if(message.isAdminMessage()){ - console.log(message); - msgList += adminMessageList(message); - } else if(message.isFileMessage()){ - if (message.type.match(/^image\/.+$/)) { - msgList +=imageMessageList(message); - } else { - msgList +=fileMessageList(message); - } - } else{ - console.log("unknown type of message :" + message); - } - }); - - $('.chat-canvas').prepend(msgList); - $('.chat-canvas')[0].scrollTop = (moreMessage.length * MESSAGE_TEXT_HEIGHT); - - for (var i in messages) { - var message = messages[i]; - updateChannelMessageCache(currChannelInfo, message); - } - - if (func) { - func(); - } - }); -} - -function messageList(message) { - var msgList = ''; - var user = message.sender; - var channel = currChannelInfo; - if (isCurrentUser(user.userId)) { - // var readReceiptHtml = ''; - // if (channel.isGroupChannel()) { - // readReceiptHtml = ' '; - // } - var readReceiptHtml = ' '; - - var msg = '' + - '
' + - ' ' + - ' ' + - ' ' + - readReceiptHtml + - '
'; - msg = msg.replace('%message%', convertLinkMessage(message.message)); - msg = msg.replace('%userid%', user.userId).replace('%messageid%', message.messageId); - - msgList += msg; - } else { - var msg = '' + - '
' + - ' ' + - ' ' + - ' ' + - '
'; - msgList += msg.replace('%userid%', user.userId).replace('%nickname%', user.nickname).replace('%messageid%', message.messageId); - } - - return msgList; -} - -function updateChannelMessageCache(channel, message) { - var readReceipt = -1; - if (channel.isGroupChannel()) { - readReceipt = channel.getReadReceipt(message); - } - if (!channelMessageList.hasOwnProperty(channel.url)) { - channelMessageList[channel.url] = {}; - } - - if (!channelMessageList[channel.url].hasOwnProperty(message.messageId)) { - channelMessageList[channel.url][message.messageId] = {}; - } - - channelMessageList[channel.url][message.messageId]['message'] = message; - - if (channel.isGroupChannel() && readReceipt >= 0) { - channelMessageList[channel.url][message.messageId]['readReceipt'] = readReceipt; - - var elemString = '.chat-canvas__list-text[data-messageid='+message.messageId+']'; - var elem = $(elemString).next(); - if (readReceipt == 0) { - elem.html('').hide(); - } else { - elem.html(readReceipt); - if (!elem.is(':visible')) { - elem.show(); - } - } - } else { - return; - } -} - -function updateChannelMessageCacheAll(channel) { - for (var i in channelMessageList[channel.url]) { - var message = channelMessageList[channel.url][i]['message']; - updateChannelMessageCache(channel, message); - } -} - -function adminMessageList(message){ - return '
' + - ' ' + - '
'; -} - -function fileMessageList(message) { - var msgList = ''; - var user = message.sender; - if (isCurrentUser(user.userId)) { - msgList += '' + - '
' + - ' ' + - ' ' + - ' ' + - '
'; - } else { - msgList += '' + - '
' + - ' ' + - ' ' + - ' ' + - '
'; - } - - // var channel = currChannelInfo; - // updateChannelMessageCache(channel, message); - - return msgList; -} - -function imageMessageList(obj) { - var msgList = ''; - var message = obj; - var user = message.sender; - if (isCurrentUser(user.userId)) { - msgList += '' + - '
' + - ' ' + - ' ' + - ' ' + - '
' + - ' ' + - '
' + - '
'; - } else { - msgList += '' + - '
' + - ' ' + - ' ' + - ' ' + - '
' + - ' ' + - '
' + - '
'; - } - - return msgList; -} - -function setWelcomeMessage(name) { - $('.chat-canvas').append( - '
' + - ' ' + - '
' - ); -} - -$('.chat-input-text__field').keydown(function (event) { - if (event.keyCode == 13 && !event.shiftKey) { - event.preventDefault(); - if (!$.trim(this.value).isEmpty()) { - event.preventDefault(); - this.value = $.trim(this.value); - - currChannelInfo.sendUserMessage($.trim(this.value), '', SendMessageHandler); - - scrollPositionBottom(); - } - this.value = ""; - } else { - if (!$.trim(this.value).isEmpty()) { - if (!currChannelInfo.isOpenChannel()) { - currChannelInfo.startTyping(); - } - } - } -}); - -$('#chat_file_input').change(function() { - if ($('#chat_file_input').val().trim().length == 0) return; - var file = $('#chat_file_input')[0].files[0]; - $('.chat-input-file').addClass('file-upload'); - - currChannelInfo.sendFileMessage(file, SendMessageHandler); -}); - -function setImageMessage(obj) { - $('.chat-canvas').append(imageMessageList(obj)); - scrollPositionBottom(); -} - -function setFileMessage(obj) { - $('.chat-canvas').append(fileMessageList(obj)); - scrollPositionBottom(); -} - -$('.chat-canvas').on('scroll', function() { - setTimeout(function() { - var currHeight = $('.chat-canvas').scrollTop(); - if (currHeight == 0) { - if ($('.chat-canvas')[0].scrollHeight > $('.chat-canvas').height()) { - loadMoreChatMessage(); - } - } - }, 200); -}); - -function setSysMessage(obj) { - $('.chat-canvas').append( - '
' + - ' ' + - '
' - ); - scrollPositionBottom(); -} - -function setBroadcastMessage(obj) { - $('.chat-canvas').append( - '
' + - ' ' + - '
' - ); - scrollPositionBottom(); -} - -function unreadCountUpdate(channel) { - var targetUrl = channel.url; - - var callAdd = true; - var unread = channel.unreadMessageCount > 9 ? '9+' : channel.unreadMessageCount; - if (unread > 0 || unread == '9+') { - $.each($('.left-nav-channel'), function(index, item) { - if ($(item).data("channel-url") == targetUrl) { - addUnreadCount(item, unread, targetUrl); - callAdd = false; - } - }); - - if (callAdd) { - showChannel(channel, unread, targetUrl); - } - } else { - showChannel(channel, unread, targetUrl); - } -} - -function addUnreadCount(item, unread, targetUrl) { - if (targetUrl == currChannelUrl) { - if (document.hasFocus()) { - return; - } - } - - if ($(item).find('div[class="left-nav-channel__unread"]').length != 0) { - $(item).find('div[class="left-nav-channel__unread"]').html(unread); - } else { - $('
' + unread + '
') - .prependTo('.left-nav-channel-group[data-channel-url='+targetUrl+']'); - } -} - -function showChannel(channel, unread, targetUrl) { - var members = channel.members; - var channelMemberList = ''; - $.each(members, function(index, member) { - if (currentUser.userId != member.userId) { - channelMemberList += member.nickname + ', '; - } - }); - channelMemberList = channelMemberList.slice(0, -2); - addGroupChannel(true, channelMemberList, channel); - - if (unread != 0) { - $.each($('.left-nav-channel'), function(index, item) { - if ($(item).data("channel-url") == targetUrl) { - addUnreadCount(item, unread, targetUrl); - } - }); - } -} -/*********************************************** - * // END Common Function - **********************************************/ - - -$('.right-section__modal-bg').click(function() { - navInit(); - popupInit(); -}); - -function navInit() { - $('.right-section__modal-bg').hide(); - - // OPEN CHAT - $('#btn_open_chat').removeClass('left-nav-open--active'); - $('.modal-open-chat').hide(); - - // MESSAGING - $('#btn_messaging_chat').removeClass('left-nav-messaging--active'); - $('.modal-messaging').hide(); -} - -function popupInit() { - $('.modal-member').hide(); - $('.chat-top__button-member').removeClass('chat-top__button-member--active'); - $('.modal-invite').hide(); - $('.chat-top__button-invite').removeClass('chat-top__button-invite--active'); -} - -function init() { - userId = decodeURI(decodeURIComponent(getUrlVars()['userid'])); - userId = checkUserId(userId); - nickname = decodeURI(decodeURIComponent(getUrlVars()['nickname'])); - - $('.init-check').show(); - startSendBird(userId, nickname); - $('.left-nav-user-nickname').html(nickname); -} - -$(document).ready(function() { - notifyMe(); - init(); -}); - -window.onfocus = function() { - if (currChannelInfo && !currChannelInfo.isOpenChannel()) { - currChannelInfo.markAsRead(); - } - $.each($('.left-nav-channel'), function(index, item) { - if ($(item).data("channel-url") == currChannelUrl) { - $(item).find('div[class="left-nav-channel__unread"]').remove(); - } - }); -}; - - diff --git a/web-sample/static/js/index.js b/web-sample/static/js/index.js deleted file mode 100644 index a3dc65a8..00000000 --- a/web-sample/static/js/index.js +++ /dev/null @@ -1,34 +0,0 @@ - -var userId = ''; -var nickname = ''; - -function login(){ - if (nickname.isEmpty()) { - alert('Please enter user nickname'); - return; - } - window.location.href = 'chat.html?userid=' + encodeURIComponent(userId) + '&nickname=' + encodeURIComponent(nickname); -} - -$('#user_nickname').change(function() { - userId = $('#user_id').val().trim(); - nickname = $('#user_nickname').val().trim(); -}); - -$('#user_nickname').keydown(function(e){ - if (e.which == 13) { - nickname = $('#user_nickname').val().trim(); - login(); - } -}); - -$('#btn_start').click(function() { - login(); -}); - -$(document).ready(function() { - $('#user_nickname').val(''); - $('#user_nickname').focus(); - - $('#user_id').val(getUserId()); -}); \ No newline at end of file diff --git a/web-sample/static/js/jquery-1.11.3.min.js b/web-sample/static/js/jquery-1.11.3.min.js deleted file mode 100644 index 0f60b7bd..00000000 --- a/web-sample/static/js/jquery-1.11.3.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery v1.11.3 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */ -!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.3",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b="length"in a&&a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,aa=/[+~]/,ba=/'|\\/g,ca=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),da=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ea=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fa){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(ba,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+ra(o[l]);w=aa.test(a)&&pa(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",ea,!1):e.attachEvent&&e.attachEvent("onunload",ea)),p=!f(g),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?la(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ca,da),a[3]=(a[3]||a[4]||a[5]||"").replace(ca,da),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ca,da).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(ca,da),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return W.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(ca,da).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:oa(function(){return[0]}),last:oa(function(a,b){return[b-1]}),eq:oa(function(a,b,c){return[0>c?c+b:c]}),even:oa(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:oa(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:oa(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:oa(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function sa(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function ta(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ua(a,b,c){for(var d=0,e=b.length;e>d;d++)ga(a,b[d],c);return c}function va(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wa(a,b,c,d,e,f){return d&&!d[u]&&(d=wa(d)),e&&!e[u]&&(e=wa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ua(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:va(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=va(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=va(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sa(function(a){return a===b},h,!0),l=sa(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sa(ta(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wa(i>1&&ta(m),i>1&&ra(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xa(a.slice(i,e)),f>e&&xa(a=a.slice(e)),f>e&&ra(a))}m.push(c)}return ta(m)}function ya(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=va(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&ga.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,ya(e,d)),f.selector=a}return f},i=ga.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ca,da),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ca,da),aa.test(j[0].type)&&pa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&ra(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,aa.test(a)&&pa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ja(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1; - -return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function aa(){return!0}function ba(){return!1}function ca(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),ha=/^\s+/,ia=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,ja=/<([\w:]+)/,ka=/\s*$/g,ra={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:k.htmlSerialize?[0,"",""]:[1,"X
","
"]},sa=da(y),ta=sa.appendChild(y.createElement("div"));ra.optgroup=ra.option,ra.tbody=ra.tfoot=ra.colgroup=ra.caption=ra.thead,ra.th=ra.td;function ua(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ua(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function va(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wa(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xa(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function ya(a){var b=pa.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function za(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Aa(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Ba(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xa(b).text=a.text,ya(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!ga.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(ta.innerHTML=a.outerHTML,ta.removeChild(f=ta.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ua(f),h=ua(a),g=0;null!=(e=h[g]);++g)d[g]&&Ba(e,d[g]);if(b)if(c)for(h=h||ua(a),d=d||ua(f),g=0;null!=(e=h[g]);g++)Aa(e,d[g]);else Aa(a,f);return d=ua(f,"script"),d.length>0&&za(d,!i&&ua(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=da(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(la.test(f)){h=h||o.appendChild(b.createElement("div")),i=(ja.exec(f)||["",""])[1].toLowerCase(),l=ra[i]||ra._default,h.innerHTML=l[1]+f.replace(ia,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&ha.test(f)&&p.push(b.createTextNode(ha.exec(f)[0])),!k.tbody){f="table"!==i||ka.test(f)?""!==l[1]||ka.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ua(p,"input"),va),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ua(o.appendChild(f),"script"),g&&za(h),c)){e=0;while(f=h[e++])oa.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wa(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wa(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ua(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&za(ua(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ua(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fa,""):void 0;if(!("string"!=typeof a||ma.test(a)||!k.htmlSerialize&&ga.test(a)||!k.leadingWhitespace&&ha.test(a)||ra[(ja.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ia,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ua(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ua(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&na.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ua(i,"script"),xa),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ua(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,ya),j=0;f>j;j++)d=g[j],oa.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qa,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Ca,Da={};function Ea(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fa(a){var b=y,c=Da[a];return c||(c=Ea(a,b),"none"!==c&&c||(Ca=(Ca||m("'; - _iframe = temp.firstChild; - container.appendChild(_iframe); - - /* _iframe.onreadystatechange = function() { - console.info(_iframe.readyState); - };*/ - - Events.addEvent(_iframe, 'load', function() { // _iframe.onload doesn't work in IE lte 8 - var el; - - try { - el = _iframe.contentWindow.document || _iframe.contentDocument || window.frames[_iframe.id].document; - - // try to detect some standard error pages - if (/^4(0[0-9]|1[0-7]|2[2346])\s/.test(el.title)) { // test if title starts with 4xx HTTP error - _status = el.title.replace(/^(\d+).*$/, '$1'); - } else { - _status = 200; - // get result - _response = Basic.trim(el.body.innerHTML); - - // we need to fire these at least once - target.trigger({ - type: 'progress', - loaded: _response.length, - total: _response.length - }); - - if (blob) { // if we were uploading a file - target.trigger({ - type: 'uploadprogress', - loaded: blob.size || 1025, - total: blob.size || 1025 - }); - } - } - } catch (ex) { - if (Url.hasSameOrigin(meta.url)) { - // if response is sent with error code, iframe in IE gets redirected to res://ieframe.dll/http_x.htm - // which obviously results to cross domain error (wtf?) - _status = 404; - } else { - cleanup.call(target, function() { - target.trigger('error'); - }); - return; - } - } - - cleanup.call(target, function() { - target.trigger('load'); - }); - }, target.uid); - } // end createIframe - - // prepare data to be sent and convert if required - if (data instanceof FormData && data.hasBlob()) { - blob = data.getBlob(); - uid = blob.uid; - input = Dom.get(uid); - form = Dom.get(uid + '_form'); - if (!form) { - throw new x.DOMException(x.DOMException.NOT_FOUND_ERR); - } - } else { - uid = Basic.guid('uid_'); - - form = document.createElement('form'); - form.setAttribute('id', uid + '_form'); - form.setAttribute('method', meta.method); - form.setAttribute('enctype', 'multipart/form-data'); - form.setAttribute('encoding', 'multipart/form-data'); - - I.getShimContainer().appendChild(form); - } - - // set upload target - form.setAttribute('target', uid + '_iframe'); - - if (data instanceof FormData) { - data.each(function(value, name) { - if (value instanceof Blob) { - if (input) { - input.setAttribute('name', name); - } - } else { - var hidden = document.createElement('input'); - - Basic.extend(hidden, { - type : 'hidden', - name : name, - value : value - }); - - // make sure that input[type="file"], if it's there, comes last - if (input) { - form.insertBefore(hidden, input); - } else { - form.appendChild(hidden); - } - } - }); - } - - // set destination url - form.setAttribute("action", meta.url); - - createIframe(); - form.submit(); - target.trigger('loadstart'); - }, - - getStatus: function() { - return _status; - }, - - getResponse: function(responseType) { - if ('json' === responseType) { - // strip off
..
tags that might be enclosing the response - if (Basic.typeOf(_response) === 'string' && !!window.JSON) { - try { - return JSON.parse(_response.replace(/^\s*]*>/, '').replace(/<\/pre>\s*$/, '')); - } catch (ex) { - return null; - } - } - } else if ('document' === responseType) { - - } - return _response; - }, - - abort: function() { - var target = this; - - if (_iframe && _iframe.contentWindow) { - if (_iframe.contentWindow.stop) { // FireFox/Safari/Chrome - _iframe.contentWindow.stop(); - } else if (_iframe.contentWindow.document.execCommand) { // IE - _iframe.contentWindow.document.execCommand('Stop'); - } else { - _iframe.src = "about:blank"; - } - } - - cleanup.call(this, function() { - // target.dispatchEvent('readystatechange'); - target.dispatchEvent('abort'); - }); - } - }); - } - - return (extensions.XMLHttpRequest = XMLHttpRequest); -}); - -// Included from: src/javascript/runtime/html4/image/Image.js - -/** - * Image.js - * - * Copyright 2013, Moxiecode Systems AB - * Released under GPL License. - * - * License: http://www.plupload.com/license - * Contributing: http://www.plupload.com/contributing - */ - -/** -@class moxie/runtime/html4/image/Image -@private -*/ -define("moxie/runtime/html4/image/Image", [ - "moxie/runtime/html4/Runtime", - "moxie/runtime/html5/image/Image" -], function(extensions, Image) { - return (extensions.Image = Image); -}); - -expose(["moxie/core/utils/Basic","moxie/core/utils/Encode","moxie/core/utils/Env","moxie/core/Exceptions","moxie/core/utils/Dom","moxie/core/EventTarget","moxie/runtime/Runtime","moxie/runtime/RuntimeClient","moxie/file/Blob","moxie/core/I18n","moxie/core/utils/Mime","moxie/file/FileInput","moxie/file/File","moxie/file/FileDrop","moxie/file/FileReader","moxie/core/utils/Url","moxie/runtime/RuntimeTarget","moxie/xhr/FormData","moxie/xhr/XMLHttpRequest","moxie/runtime/Transporter","moxie/image/Image","moxie/core/utils/Events","moxie/runtime/html5/image/ResizerCanvas"]); -})(this); -})); \ No newline at end of file diff --git a/web-sample/static/lib/swfobject.js b/web-sample/static/lib/swfobject.js deleted file mode 100644 index 8eafe9dd..00000000 --- a/web-sample/static/lib/swfobject.js +++ /dev/null @@ -1,4 +0,0 @@ -/* SWFObject v2.2 - is released under the MIT License -*/ -var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y0){for(var af=0;af0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad'}}aa.outerHTML='"+af+"";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab -// License: New BSD License -// Reference: http://dev.w3.org/html5/websockets/ -// Reference: http://tools.ietf.org/html/rfc6455 - -(function() { - - if (window.WEB_SOCKET_FORCE_FLASH) { - // Keeps going. - } else if (window.WebSocket) { - return; - } else if (window.MozWebSocket) { - // Firefox. - window.WebSocket = MozWebSocket; - return; - } - - var logger; - if (window.WEB_SOCKET_LOGGER) { - logger = WEB_SOCKET_LOGGER; - } else if (window.console && window.console.log && window.console.error) { - // In some environment, console is defined but console.log or console.error is missing. - logger = window.console; - } else { - logger = {log: function(){ }, error: function(){ }}; - } - - // swfobject.hasFlashPlayerVersion("10.0.0") doesn't work with Gnash. - if (swfobject.getFlashPlayerVersion().major < 10) { - logger.error("Flash Player >= 10.0.0 is required."); - return; - } - if (location.protocol == "file:") { - logger.error( - "WARNING: web-socket-js doesn't work in file:///... URL " + - "unless you set Flash Security Settings properly. " + - "Open the page via Web server i.e. http://..."); - } - - /** - * Our own implementation of WebSocket class using Flash. - * @param {string} url - * @param {array or string} protocols - * @param {string} proxyHost - * @param {int} proxyPort - * @param {string} headers - */ - window.WebSocket = function(url, protocols, proxyHost, proxyPort, headers) { - var self = this; - self.__id = WebSocket.__nextId++; - WebSocket.__instances[self.__id] = self; - self.readyState = WebSocket.CONNECTING; - self.bufferedAmount = 0; - self.__events = {}; - if (!protocols) { - protocols = []; - } else if (typeof protocols == "string") { - protocols = [protocols]; - } - // Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc. - // Otherwise, when onopen fires immediately, onopen is called before it is set. - self.__createTask = setTimeout(function() { - WebSocket.__addTask(function() { - self.__createTask = null; - WebSocket.__flash.create( - self.__id, url, protocols, proxyHost || null, proxyPort || 0, headers || null); - }); - }, 0); - }; - - /** - * Send data to the web socket. - * @param {string} data The data to send to the socket. - * @return {boolean} True for success, false for failure. - */ - WebSocket.prototype.send = function(data) { - if (this.readyState == WebSocket.CONNECTING) { - throw "INVALID_STATE_ERR: Web Socket connection has not been established"; - } - // We use encodeURIComponent() here, because FABridge doesn't work if - // the argument includes some characters. We don't use escape() here - // because of this: - // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions - // But it looks decodeURIComponent(encodeURIComponent(s)) doesn't - // preserve all Unicode characters either e.g. "\uffff" in Firefox. - // Note by wtritch: Hopefully this will not be necessary using ExternalInterface. Will require - // additional testing. - var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data)); - if (result < 0) { // success - return true; - } else { - this.bufferedAmount += result; - return false; - } - }; - - /** - * Close this web socket gracefully. - */ - WebSocket.prototype.close = function() { - if (this.__createTask) { - clearTimeout(this.__createTask); - this.__createTask = null; - this.readyState = WebSocket.CLOSED; - return; - } - if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) { - return; - } - this.readyState = WebSocket.CLOSING; - WebSocket.__flash.close(this.__id); - }; - - /** - * Implementation of {@link DOM 2 EventTarget Interface} - * - * @param {string} type - * @param {function} listener - * @param {boolean} useCapture - * @return void - */ - WebSocket.prototype.addEventListener = function(type, listener, useCapture) { - if (!(type in this.__events)) { - this.__events[type] = []; - } - this.__events[type].push(listener); - }; - - /** - * Implementation of {@link DOM 2 EventTarget Interface} - * - * @param {string} type - * @param {function} listener - * @param {boolean} useCapture - * @return void - */ - WebSocket.prototype.removeEventListener = function(type, listener, useCapture) { - if (!(type in this.__events)) return; - var events = this.__events[type]; - for (var i = events.length - 1; i >= 0; --i) { - if (events[i] === listener) { - events.splice(i, 1); - break; - } - } - }; - - /** - * Implementation of {@link DOM 2 EventTarget Interface} - * - * @param {Event} event - * @return void - */ - WebSocket.prototype.dispatchEvent = function(event) { - var events = this.__events[event.type] || []; - for (var i = 0; i < events.length; ++i) { - events[i](event); - } - var handler = this["on" + event.type]; - if (handler) handler.apply(this, [event]); - }; - - /** - * Handles an event from Flash. - * @param {Object} flashEvent - */ - WebSocket.prototype.__handleEvent = function(flashEvent) { - - if ("readyState" in flashEvent) { - this.readyState = flashEvent.readyState; - } - if ("protocol" in flashEvent) { - this.protocol = flashEvent.protocol; - } - - var jsEvent; - if (flashEvent.type == "open" || flashEvent.type == "error") { - jsEvent = this.__createSimpleEvent(flashEvent.type); - } else if (flashEvent.type == "close") { - jsEvent = this.__createSimpleEvent("close"); - jsEvent.wasClean = flashEvent.wasClean ? true : false; - jsEvent.code = flashEvent.code; - jsEvent.reason = flashEvent.reason; - } else if (flashEvent.type == "message") { - var data = decodeURIComponent(flashEvent.message); - jsEvent = this.__createMessageEvent("message", data); - } else { - throw "unknown event type: " + flashEvent.type; - } - - this.dispatchEvent(jsEvent); - - }; - - WebSocket.prototype.__createSimpleEvent = function(type) { - if (document.createEvent && window.Event) { - var event = document.createEvent("Event"); - event.initEvent(type, false, false); - return event; - } else { - return {type: type, bubbles: false, cancelable: false}; - } - }; - - WebSocket.prototype.__createMessageEvent = function(type, data) { - if (window.MessageEvent && typeof(MessageEvent) == "function" && !window.opera) { - return new MessageEvent("message", { - "view": window, - "bubbles": false, - "cancelable": false, - "data": data - }); - } else if (document.createEvent && window.MessageEvent && !window.opera) { - var event = document.createEvent("MessageEvent"); - event.initMessageEvent("message", false, false, data, null, null, window, null); - return event; - } else { - // Old IE and Opera, the latter one truncates the data parameter after any 0x00 bytes. - return {type: type, data: data, bubbles: false, cancelable: false}; - } - }; - - /** - * Define the WebSocket readyState enumeration. - */ - WebSocket.CONNECTING = 0; - WebSocket.OPEN = 1; - WebSocket.CLOSING = 2; - WebSocket.CLOSED = 3; - - // Field to check implementation of WebSocket. - WebSocket.__isFlashImplementation = true; - WebSocket.__initialized = false; - WebSocket.__flash = null; - WebSocket.__instances = {}; - WebSocket.__tasks = []; - WebSocket.__nextId = 0; - - /** - * Load a new flash security policy file. - * @param {string} url - */ - WebSocket.loadFlashPolicyFile = function(url){ - WebSocket.__addTask(function() { - WebSocket.__flash.loadManualPolicyFile(url); - }); - }; - - /** - * Loads WebSocketMain.swf and creates WebSocketMain object in Flash. - */ - WebSocket.__initialize = function() { - - if (WebSocket.__initialized) return; - WebSocket.__initialized = true; - - if (WebSocket.__swfLocation) { - // For backword compatibility. - window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation; - } - if (!window.WEB_SOCKET_SWF_LOCATION) { - logger.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf"); - return; - } - if (!window.WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR && - !WEB_SOCKET_SWF_LOCATION.match(/(^|\/)WebSocketMainInsecure\.swf(\?.*)?$/) && - WEB_SOCKET_SWF_LOCATION.match(/^\w+:\/\/([^\/]+)/)) { - var swfHost = RegExp.$1; - if (location.host != swfHost) { - logger.error( - "[WebSocket] You must host HTML and WebSocketMain.swf in the same host " + - "('" + location.host + "' != '" + swfHost + "'). " + - "See also 'How to host HTML file and SWF file in different domains' section " + - "in README.md. If you use WebSocketMainInsecure.swf, you can suppress this message " + - "by WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR = true;"); - } - } - var container = document.createElement("div"); - container.id = "webSocketContainer"; - // Hides Flash box. We cannot use display: none or visibility: hidden because it prevents - // Flash from loading at least in IE. So we move it out of the screen at (-100, -100). - // But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash - // Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is - // the best we can do as far as we know now. - container.style.position = "absolute"; - if (WebSocket.__isFlashLite()) { - container.style.left = "0px"; - container.style.top = "0px"; - } else { - container.style.left = "-100px"; - container.style.top = "-100px"; - } - var holder = document.createElement("div"); - holder.id = "webSocketFlash"; - container.appendChild(holder); - document.body.appendChild(container); - // See this article for hasPriority: - // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html - swfobject.embedSWF( - WEB_SOCKET_SWF_LOCATION, - "webSocketFlash", - "1" /* width */, - "1" /* height */, - "10.0.0" /* SWF version */, - null, - null, - {hasPriority: true, swliveconnect : true, allowScriptAccess: "always"}, - null, - function(e) { - if (!e.success) { - logger.error("[WebSocket] swfobject.embedSWF failed"); - } - } - ); - - }; - - /** - * Called by Flash to notify JS that it's fully loaded and ready - * for communication. - */ - WebSocket.__onFlashInitialized = function() { - // We need to set a timeout here to avoid round-trip calls - // to flash during the initialization process. - setTimeout(function() { - WebSocket.__flash = document.getElementById("webSocketFlash"); - WebSocket.__flash.setCallerUrl(location.href); - WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG); - for (var i = 0; i < WebSocket.__tasks.length; ++i) { - WebSocket.__tasks[i](); - } - WebSocket.__tasks = []; - }, 0); - }; - - /** - * Called by Flash to notify WebSockets events are fired. - */ - WebSocket.__onFlashEvent = function() { - setTimeout(function() { - try { - // Gets events using receiveEvents() instead of getting it from event object - // of Flash event. This is to make sure to keep message order. - // It seems sometimes Flash events don't arrive in the same order as they are sent. - var events = WebSocket.__flash.receiveEvents(); - for (var i = 0; i < events.length; ++i) { - WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]); - } - } catch (e) { - logger.error(e); - } - }, 0); - return true; - }; - - // Called by Flash. - WebSocket.__log = function(message) { - logger.log(decodeURIComponent(message)); - }; - - // Called by Flash. - WebSocket.__error = function(message) { - logger.error(decodeURIComponent(message)); - }; - - WebSocket.__addTask = function(task) { - if (WebSocket.__flash) { - task(); - } else { - WebSocket.__tasks.push(task); - } - }; - - /** - * Test if the browser is running flash lite. - * @return {boolean} True if flash lite is running, false otherwise. - */ - WebSocket.__isFlashLite = function() { - if (!window.navigator || !window.navigator.mimeTypes) { - return false; - } - var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"]; - if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) { - return false; - } - return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false; - }; - - if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) { - // NOTE: - // This fires immediately if web_socket.js is dynamically loaded after - // the document is loaded. - swfobject.addDomLoadEvent(function() { - WebSocket.__initialize(); - }); - } - -})(); diff --git a/web-widget/README.md b/web-widget/README.md deleted file mode 100644 index f0337281..00000000 --- a/web-widget/README.md +++ /dev/null @@ -1,127 +0,0 @@ -# SendBird JavaScript Widget Sample -This is a sample chat widget built using using the [SendBird SDK](https://github.com/smilefam/SendBird-SDK-JavaScript). It can be used to add a functional chat widget to any website. - - -## [Demo](https://sample.sendbird.com/widget/) - -You can try out a live demo from the link [here](https://sample.sendbird.com/widget/). Click on the button at the bottom-right corner of the webpage to try out the widget. Choose any 'User ID' and 'Nickname' to log in and participate in chats. - - -## Setup -1. The `body` must have a `div` element whose id is `sb_widget`. - -```html - -
- -``` - -2. Import the [`SendBird SDK`](https://github.com/smilefam/SendBird-SDK-JavaScript). -3. Import the `widget.SendBird.js` file. -```javascript - - -``` - - -## Customizing the widget -If you refresh your browser window, you need to reconnect to SendBird. To retain connection on browser refresh, you must implement an appropriate `event handler`. - -If you wish to issue an `access_token` for your user, modify the `connect function` in `src/sendbird.js`. - -1. Install npm - - npm install --save-dev - -2. Modify files. -3. Create a bundle file. - - webpack -p - - -## Advanced -### Connect other APP or Channel -If you want to connect other application, you need to change variable `appId` in `index.html`. - -```html -... - - - - - - -``` - -### Start with User connect -If you want to start this sample with user connect, you can using `startWithConnect()`. - -```html -... - - - - - - -``` - -### Show Channel -If you want to open chat, you can using `showChannel()`. - -```javascript -... -var channelUrl = ''; -sbWidget.showChannel(channelUrl); -... -``` - - -## File Structure -``` - |-- build - |-- widget.SendBird.js - SendBird Widget Bundle file - |-- node_modules - |-- ... - (node packages) - |-- src - |-- js - |-- elements - |-- elements.js - elements root class - |-- spinner.js - spinner element - |-- widget-btn.js - widget button element - |-- popup.js - popup element - |-- list-board.js - channel list element - |-- chat-section.js - chat element - |-- consts.js - const variables - |-- utils.js - util functions - |-- sendbird.js - sendbird functions - |-- widget.js - widget functions - |-- scss - |-- mixins - |-- _border-radius.scss - border radius mixin - |-- _box-shadow.scss - box shadow mixin - |-- _state.scss - element state mixin - |-- _transform.scss - transform mixin - |-- _reset.scss - clean css mixin - |-- _mixins.scss - import mixin - |-- _variables.scss - css variables - |-- _animation.scss - animation - |-- _icons.scss - icon - |-- widget.scss - main css -|-- .eslintrc.js - lint setting -|-- webpack.config.js - webpack setting -|-- package.json - npm package -|-- SendBird.min.js - SendBird SDK -|-- index.html - sample file -|-- README.md -``` diff --git a/web-widget/SendBird.min.js b/web-widget/SendBird.min.js deleted file mode 100644 index c093b4ef..00000000 --- a/web-widget/SendBird.min.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Copyright (c) 2016 SendBird DBA (Smile Family, Inc.) - * SendBird JavaScript SDK v3.0.31 - */ -!function(root,factory){"object"==typeof exports&&"object"==typeof module?module.exports=factory():"function"==typeof define&&define.amd?define([],factory()):"object"==typeof exports?exports.SendBird=factory():(root.SendBird=factory(),root.SendBird2=factory())}(this,function(){function isIE9(){try{if(document&&9==document.documentMode)return!0}catch(err){}return!1}function isIE8Less(){try{if(document&&document.documentMode<=8)return!0}catch(err){}return!1}function FormDataIE(){this.oldIE=!0,this.boundary="--------FormData"+Math.random(),this._fields=[]}var DEBUG=!1,DEBUG_HOST=!1,WS_HOST="wss://ws.sendbird.com",API_HOST="https://api.sendbird.com";DEBUG_HOST&&(WS_HOST="ws://localtest.me:9700",API_HOST="http://api.localtest.me:9800");var console;try{console=window.console||{log:function(){}}}catch(e){console={log:function(){}}}var OS_VERSION="undefined";try{OS_VERSION=navigator.userAgent.replace(/,/g,".")}catch(e){OS_VERSION="undefined"}var _Xhr,API_HEADER_PARAM="JS,"+OS_VERSION+",3.0.31,";try{_Xhr="undefined"==typeof window?require("xhr2"):null}catch(err){_Xhr=null}if(_Xhr)try{var Agent=require("agentkeepalive"),HttpsAgent=require("agentkeepalive").HttpsAgent,options={},nodejsHttpAgent=new Agent({keepAlive:!0,timeout:6e4,keepAliveTimeout:6e4});options.httpAgent=nodejsHttpAgent;var nodejsHttpsAgent=new HttpsAgent({keepAlive:!0,timeout:6e4,keepAliveTimeout:6e4});options.httpsAgent=nodejsHttpsAgent,_Xhr.nodejsSet(options)}catch(e){}var _FormData,isIE9=isIE9(),isIE8Less=isIE8Less();if(isIE9||isIE8Less)"function"!=typeof String.prototype.trim&&(String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"")}),"function"!=typeof Array.prototype.forEach&&(Array.prototype.forEach=function(callback){for(var i=0;i=200&&request.status<400?_cb_wrapper(null,JSON.parse(request.responseText),cb):_cb_wrapper({status:request.status,statusText:request.statusText,response:request.responseText},null,cb)},request.onerror=function(){_cb_wrapper({status:404,statusText:"There was a connection error"},null,cb)};try{for(var i in header)request.setRequestHeader(i,header[i]?header[i]:"sendbird")}catch(e){}try{switch(method){case"get":case"GET":request.send();break;default:"undefined"!=typeof FormData&&FormData&&data instanceof FormData||void 0!==_FormData&&_FormData&&data instanceof _FormData?data.oldIE?(request.setRequestHeader("Content-Type","multipart/form-data; boundary="+data.boundary),request.send(data.toString())):request.send(data):(request.setRequestHeader("Content-Type","application/json; charset=utf-8"),request.send(JSON.stringify(data)))}}catch(e){console.log("request.send() fail:"+e)}},_inherit=function(){var F=function(){};return function(Parent,Child){F.prototype=new Parent,Child.prototype=new F,Child["super"]=Parent.prototype,Child.prototype.constructor=Child}}(),SendBirdException=function(_message,_code){return this.name="SendBirdException",this.code=_code||0,this.message=_message,this};_inherit(Error,SendBirdException);var SendBirdObject=function(){var errorFirstCallback=!1,callbackWrapper=function(result,error,cb){cb&&"function"==typeof cb&&(void 0===error&&(error=null),void 0===result&&(result=null),errorFirstCallback?cb(error,result):cb(result,error))},appId="",reconnectCount=0,reconnectDelay=0,BaseMessage=function(jsonObject){this.isOpenChannel=function(){return this.channelType==BaseChannel.CHANNEL_TYPE_OPEN},this.isGroupChannel=function(){return this.channelType==BaseChannel.CHANNEL_TYPE_GROUP},this.isUserMessage=function(){return this.messageType==BaseMessage.MESSAGE_TYPE_USER},this.isAdminMessage=function(){return this.messageType==BaseMessage.MESSAGE_TYPE_ADMIN},this.isFileMessage=function(){return this.messageType==BaseMessage.MESSAGE_TYPE_FILE},this._update=function(jsonObject){this.messageId=jsonObject.hasOwnProperty("msg_id")?parseInt(jsonObject.msg_id):0,this.channelUrl=jsonObject.hasOwnProperty("channel_url")?String(jsonObject.channel_url):"",this.createdAt=jsonObject.hasOwnProperty("ts")?parseInt(jsonObject.ts):0,this.updatedAt=jsonObject.hasOwnProperty("updated_at")?parseInt(jsonObject.updated_at):0,this.channelType=jsonObject.hasOwnProperty("channel_type")?String(jsonObject.channel_type):BaseChannel.CHANNEL_TYPE_GROUP},this.messageType=BaseMessage.MESSAGE_TYPE_BASE,jsonObject&&this._update(jsonObject)};BaseMessage.build=function(jsonObject,channel){if(!jsonObject)return null;var user,msgId,message,data,createdAt,updatedAt,customType,translations;switch(jsonObject.type){case"MESG":return user=new User(jsonObject.user),msgId=parseInt(jsonObject.message_id),message=String(jsonObject.message),data=String(jsonObject.data),createdAt=parseInt(jsonObject.created_at),updatedAt=parseInt(jsonObject.updated_at),customType=jsonObject.hasOwnProperty("custom_type")?String(jsonObject.custom_type):"",translations=jsonObject.hasOwnProperty("translations")?jsonObject.translations:{},new UserMessage(UserMessage.build("",msgId,user,channel,message,data,customType,translations,createdAt,updatedAt));case"FILE":user=new User(jsonObject.user),msgId=parseInt(jsonObject.message_id),message=String(jsonObject.message),createdAt=parseInt(jsonObject.created_at),updatedAt=parseInt(jsonObject.updated_at),customType=jsonObject.hasOwnProperty("custom_type")?String(jsonObject.custom_type):"";var file=jsonObject.file,url=String(file.url),name=String(file.name),fileType=String(file.type),size=parseInt(file.size)||0;data=String(file.data);var thumbnails=jsonObject.hasOwnProperty("thumbnails")?jsonObject.thumbnails:[],requireAuth=!!jsonObject.hasOwnProperty("require_auth")&&jsonObject.require_auth;return new FileMessage(FileMessage.build("",msgId,user,channel,url,name,fileType,size,data,customType,createdAt,thumbnails,requireAuth,updatedAt));case"BRDM":case"ADMM":return msgId=parseInt(jsonObject.message_id),message=String(jsonObject.message),data=String(jsonObject.data),createdAt=parseInt(jsonObject.created_at),updatedAt=parseInt(jsonObject.updated_at),customType=jsonObject.hasOwnProperty("custom_type")?String(jsonObject.custom_type):"",translations=jsonObject.hasOwnProperty("translations")?jsonObject.translations:{},new AdminMessage(AdminMessage.build(msgId,channel,message,data,customType,translations,createdAt,updatedAt))}return null},BaseMessage.MESSAGE_TYPE_BASE="base",BaseMessage.MESSAGE_TYPE_ADMIN="admin",BaseMessage.MESSAGE_TYPE_USER="user",BaseMessage.MESSAGE_TYPE_FILE="file";var AdminMessage=function(jsonObject){this.messageType=BaseMessage.MESSAGE_TYPE_ADMIN,jsonObject&&(this._update(jsonObject),this.message=String(jsonObject.message),this.data=jsonObject.hasOwnProperty("data")?String(jsonObject.data):"",this.customType=jsonObject.hasOwnProperty("custom_type")?String(jsonObject.custom_type):"",this.translations=jsonObject.hasOwnProperty("translations")?jsonObject.translations:{})};_inherit(BaseMessage,AdminMessage),AdminMessage.build=function(msgId,channel,message,data,customType,translations,createdAt,updatedAt){var obj={msg_id:msgId,channel_url:channel.url,channel_type:channel.isOpenChannel()?BaseChannel.CHANNEL_TYPE_OPEN:BaseChannel.CHANNEL_TYPE_GROUP,ts:createdAt,updated_at:updatedAt,message:message,data:data};return customType&&(obj.custom_type=customType),translations&&(obj.translations=translations),obj};var UserMessage=function(jsonObject){this.messageType=BaseMessage.MESSAGE_TYPE_USER,jsonObject&&(this._update(jsonObject),this.message=String(jsonObject.message),this.data=jsonObject.hasOwnProperty("data")?String(jsonObject.data):"",this._sender=new User(jsonObject.user),isIE8Less?this.sender=this._sender:Object.defineProperty(this,"sender",{get:function(){if(SendBird.getInstance().Options.UseMemberAsMessageSender&&this.isGroupChannel()){var currentChannel=GroupChannel.cachedChannels[this.channelUrl];if(currentChannel){var member=currentChannel.memberMap[this._sender.userId];member&&(this._sender.nickname!=member.nickname&&(this._sender.nickname=member.nickname),this._sender.profileUrl!=member.profileUrl&&(this._sender.profileUrl=member.profileUrl))}}return this._sender},set:function(val){this._sender=val}}),this.reqId=jsonObject.hasOwnProperty("req_id")?String(jsonObject.req_id):"",this.customType=jsonObject.hasOwnProperty("custom_type")?String(jsonObject.custom_type):"",this.translations=jsonObject.hasOwnProperty("translations")?jsonObject.translations:{})};_inherit(BaseMessage,UserMessage),UserMessage.build=function(requestId,msgId,user,channel,message,data,customType,translations,createdAt,updatedAt){var obj={};obj.req_id=requestId,obj.msg_id=msgId,obj.channel_url=channel.url,obj.channel_type=channel.channelType==BaseChannel.CHANNEL_TYPE_OPEN?BaseChannel.CHANNEL_TYPE_OPEN:BaseChannel.CHANNEL_TYPE_GROUP,obj.ts=createdAt,obj.updated_at=updatedAt,obj.message=message,data&&(obj.data=data),customType&&(obj.custom_type=customType),translations&&(obj.translations=translations);var userObj={};return userObj.user_id=user.userId,userObj.nickname=user.nickname,userObj.profile_url=user.profileUrl,obj.user=userObj,obj};var FileMessage=function(jsonObject){if(this.messageType=BaseMessage.MESSAGE_TYPE_FILE,jsonObject&&(this._update(jsonObject),this._sender=new User(jsonObject.user),isIE8Less?this.sender=this._sender:Object.defineProperty(this,"sender",{get:function(){if(SendBird.getInstance().Options.UseMemberAsMessageSender&&this.isGroupChannel()){var currentChannel=GroupChannel.cachedChannels[this.channelUrl];if(currentChannel){var member=currentChannel.memberMap[this._sender.userId];member&&(this._sender.nickname!=member.nickname&&(this._sender.nickname=member.nickname),this._sender.profileUrl!=member.profileUrl&&(this._sender.profileUrl=member.profileUrl))}}return this._sender},set:function(val){this._sender=val}}),this.requireAuth=!!jsonObject.hasOwnProperty("require_auth")&&jsonObject.require_auth,this.url=this.requireAuth?String(jsonObject.url)+"?auth="+APIClient.getInstance().ekey:String(jsonObject.url),this.name=jsonObject.hasOwnProperty("name")?jsonObject.name:"File",this.size=parseInt(jsonObject.size)||0,this.type=String(jsonObject.type),this.data=jsonObject.hasOwnProperty("custom")?String(jsonObject.custom):"",this.reqId=jsonObject.hasOwnProperty("req_id")?String(jsonObject.req_id):"",this.customType=jsonObject.hasOwnProperty("custom_type")?String(jsonObject.custom_type):"",this.thumbnails=jsonObject.hasOwnProperty("thumbnails")?jsonObject.thumbnails:[],this.requireAuth))for(var i in this.thumbnails)this.thumbnails[i].url+="?auth="+APIClient.getInstance().ekey};_inherit(BaseMessage,FileMessage),FileMessage.build=function(requestId,msgId,user,channel,url,name,type,size,data,customType,createdAt,thumbnails,requireAuth,updatedAt){var obj={};obj.req_id=requestId,obj.msg_id=msgId,obj.channel_url=channel.url,obj.channel_type=channel.channelType==BaseChannel.CHANNEL_TYPE_OPEN?BaseChannel.CHANNEL_TYPE_OPEN:BaseChannel.CHANNEL_TYPE_GROUP,obj.ts=createdAt,obj.updated_at=updatedAt,obj.url=url,obj.name=name,obj.type=type,obj.size=size,obj.custom=data;var userObj={};return userObj.user_id=user.userId,userObj.nickname=user.nickname,userObj.profile_url=user.profileUrl,obj.user=userObj,customType&&(obj.custom_type=customType),requireAuth&&(obj.require_auth=requireAuth),thumbnails&&(obj.thumbnails=thumbnails),obj};var BaseChannel=function(jsonObject){this._update=function(jsonObject){this.url=String(jsonObject.channel_url),this.name=String(jsonObject.name),this.coverUrl=String(jsonObject.cover_url),this.createdAt=jsonObject.hasOwnProperty("created_at")?1e3*jsonObject.created_at:0,this.data=String(jsonObject.data),this.customType=jsonObject.hasOwnProperty("custom_type")?jsonObject.custom_type:"",this.fileUploadRequest={}},this.isGroupChannel=function(){return this.channelType==BaseChannel.CHANNEL_TYPE_GROUP},this.isOpenChannel=function(){return this.channelType==BaseChannel.CHANNEL_TYPE_OPEN},this.createPreviousMessageListQuery=function(){return new PreviousMessageListQuery(this)},this.createMessageListQuery=function(){return new MessageListQuery(this)};var _getMessagesByTimestamp=function(channel,ts,isInclusive,prevResultSize,nextResultSize,shouldReverse,messageType,customType,cb){APIClient.getInstance().messageList(channel.isOpenChannel(),channel.url,ts,prevResultSize,nextResultSize,isInclusive,shouldReverse,messageType,customType,function(response,error){if(error)return void callbackWrapper(null,error,cb);var objs=response.messages,messages=[];for(var i in objs){var msg=BaseMessage.build(objs[i],channel);msg&&messages.push(msg)}callbackWrapper(messages,null,cb)})},_getMessagesByID=function(channel,msgID,isInclusive,prevResultSize,nextResultSize,shouldReverse,messageType,customType,cb){APIClient.getInstance().messageListByID(channel.isOpenChannel(),channel.url,msgID,prevResultSize,nextResultSize,isInclusive,shouldReverse,messageType,customType,function(response,error){if(error)return void callbackWrapper(null,error,cb);var objs=response.messages,messages=[];for(var i in objs){var msg=BaseMessage.build(objs[i],channel);msg&&messages.push(msg)}callbackWrapper(messages,null,cb)})};this.getNextMessagesByTimestamp=function(ts,isInclusive,nextResultSize,shouldReverse,messageType,customType,cb){return _SELF=this,_getMessagesByTimestamp(_SELF,ts,isInclusive,0,nextResultSize,shouldReverse,messageType,customType,cb)},this.getPreviousMessagesByTimestamp=function(ts,isInclusive,prevResultSize,shouldReverse,messageType,customType,cb){return _SELF=this,_getMessagesByTimestamp(_SELF,ts,isInclusive,prevResultSize,0,shouldReverse,messageType,customType,cb)},this.getPreviousAndNextMessagesByTimestamp=function(ts,prevResultSize,nextResultSize,shouldReverse,messageType,customType,cb){return _SELF=this,_getMessagesByTimestamp(_SELF,ts,!0,prevResultSize,nextResultSize,shouldReverse,messageType,customType,cb)},this.getNextMessagesByID=function(msgId,isInclusive,nextResultSize,shouldReverse,messageType,customType,cb){return _SELF=this,_getMessagesByID(_SELF,msgId,isInclusive,0,nextResultSize,shouldReverse,messageType,customType,cb)},this.getPreviousMessagesByID=function(msgId,isInclusive,prevResultSize,shouldReverse,messageType,customType,cb){return _SELF=this,_getMessagesByID(_SELF,msgId,isInclusive,prevResultSize,0,shouldReverse,messageType,customType,cb)},this.getPreviousAndNextMessagesByID=function(msgId,prevResultSize,nextResultSize,shouldReverse,messageType,customType,cb){return _SELF=this,_getMessagesByID(_SELF,msgId,!0,prevResultSize,nextResultSize,shouldReverse,messageType,customType,cb)},this._sendFileCommand=function(channelUrl,fileUrl,name,type,size,data,customType,thumbnails,requireAuth,callback,preMessageObj){var requestId;requestId=preMessageObj?preMessageObj.reqId:Command.generateRequestId();var command=Command.bFile(requestId,channelUrl,fileUrl,name,type,size,data,customType,thumbnails,requireAuth),msgObj=FileMessage.build(command.requestId,0,SendBird.getInstance().currentUser,this,"string"==typeof fileUrl?fileUrl:"",name,type,size,data,customType,null,null,!1),msg=new FileMessage(msgObj);return"string"==typeof fileUrl&&SendBird.getInstance().sendCommand(command,function(ackedCommand,error){if(error)return void callbackWrapper(null,new SendBirdException(error.message,error.code),callback);var fileMessage=new FileMessage(ackedCommand.getJsonElement()),me=SendBird.getInstance().currentUser;me&&fileMessage._sender&&me.userId==fileMessage._sender.userId&&(me.nickname!=fileMessage._sender.nickname&&(me.nickname=fileMessage._sender.nickname),me.profileUrl!=fileMessage._sender.profileUrl&&(me.profileUrl=fileMessage._sender.profileUrl)),callbackWrapper(fileMessage,null,callback)}),msg},this._getSendFileMessageParamInfo=function(args){var fileMessageInfo={file:null,name:"",type:"",size:0,data:"",customType:"",thumbnailSizes:[],callback:null,progressHandler:null};switch("function"==typeof args.slice(-1)[0]&&(fileMessageInfo.callback=args.pop()),"function"==typeof args.slice(-1)[0]&&(fileMessageInfo.progressHandler=args.pop()),args.length){case 1:fileMessageInfo.file=args[0];break;case 2:fileMessageInfo.file=args[0],fileMessageInfo.data=args[1];break;case 3:fileMessageInfo.file=args[0],fileMessageInfo.data=args[1],fileMessageInfo.customType=args[2];break;case 4:fileMessageInfo.file=args[0],fileMessageInfo.data=args[1],fileMessageInfo.customType=args[2],fileMessageInfo.thumbnailSizes=args[3];break;case 5:fileMessageInfo.file=args[0],fileMessageInfo.name=args[1],fileMessageInfo.type=args[2],fileMessageInfo.size=args[3],fileMessageInfo.data=args[4];break;case 6:fileMessageInfo.file=args[0],fileMessageInfo.name=args[1],fileMessageInfo.type=args[2],fileMessageInfo.size=args[3],fileMessageInfo.data=args[4],fileMessageInfo.customType=args[5];break;case 7:fileMessageInfo.file=args[0],fileMessageInfo.name=args[1],fileMessageInfo.type=args[2],fileMessageInfo.size=args[3],fileMessageInfo.data=args[4],fileMessageInfo.customType=args[5],fileMessageInfo.thumbnailSizes=args[6]}return"string"!=typeof fileMessageInfo.file&&(fileMessageInfo.name=fileMessageInfo.file.name,fileMessageInfo.type=fileMessageInfo.file.type,fileMessageInfo.size=fileMessageInfo.file.size),fileMessageInfo},this.sendFileMessage=function(){var _SELF=this,fileInfo=this._getSendFileMessageParamInfo(Array.prototype.slice.call(arguments)),file=fileInfo.file,name=fileInfo.name,type=fileInfo.type,size=fileInfo.size,data=fileInfo.data,customType=fileInfo.customType,thumbnailSizes=fileInfo.thumbnailSizes,callback=fileInfo.callback,progressHandler=fileInfo.progressHandler,channelUrl=_SELF.url,msg=null;return"string"==typeof file?msg=_SELF._sendFileCommand(channelUrl,file,name,type,size,data,customType,[],!1,callback):(msg=_SELF._sendFileCommand(channelUrl,file,name,type,size,data,customType,[],!1,callback),APIClient.getInstance().uploadFile(file,type,thumbnailSizes,channelUrl,function(response,error){if(error)return void callbackWrapper(null,error,callback);var result="object"==typeof response?response:JSON.parse(response),fileUrl=result.url,thumbnails=result.hasOwnProperty("thumbnails")?result.thumbnails:[],requireAuth=!!result.hasOwnProperty("require_auth")&&result.require_auth;_SELF._sendFileCommand(channelUrl,fileUrl,name,type,size,data,customType,thumbnails,requireAuth,callback,msg)},progressHandler,this.fileUploadRequest,msg.reqId)),msg},this.cancelUploadingFileMessage=function(messageReqId,cb){var _SELF=this,xhr=_SELF.fileUploadRequest[messageReqId];return xhr?(xhr.upload.onabort=function(e){delete _SELF.fileUploadRequest[messageReqId],callbackWrapper(!0,null,cb)},xhr.abort(),!0):(callbackWrapper(!1,new SendBirdException("Uploading has been completed or cancelled.",SendBirdError.FILE_UPLOAD_CANCEL_FAILED),cb),!1)},this.sendUserMessage=function(message,data,customType,targetLanguages,cb){"function"==typeof data&&(cb=data,data="",customType="",targetLanguages=[]),"function"==typeof customType&&(cb=customType,customType="",targetLanguages=[]),"function"==typeof targetLanguages&&(cb=targetLanguages,targetLanguages=[]),targetLanguages||(targetLanguages=[]),"string"==typeof targetLanguages&&(targetLanguages=[targetLanguages]);var cmd=Command.bMessage(this.url,message,data,customType,[],targetLanguages),msgObj=UserMessage.build(cmd.requestId,0,SendBird.getInstance().currentUser,this,message,data,customType,targetLanguages,(new Date).getTime()),msg=new UserMessage(msgObj);return SendBird.getInstance().sendCommand(cmd,function(ackedCommand,error){if(error)return void callbackWrapper(null,new SendBirdException(error.message,error.code),cb);var userMessage=new UserMessage(ackedCommand.getJsonElement()),me=SendBird.getInstance().currentUser;me&&userMessage._sender&&me.userId==userMessage._sender.userId&&(me.nickname!=userMessage._sender.nickname&&(me.nickname=userMessage._sender.nickname),me.profileUrl!=userMessage._sender.profileUrl&&(me.profileUrl=userMessage._sender.profileUrl)),callbackWrapper(userMessage,null,cb)}),msg},this.updateUserMessage=function(messageId,message,data,customType,cb){var _targetLanguages=[],cmd=Command.bUpdateUserMessage(this.url,messageId,message,data,customType),msgObj=UserMessage.build(cmd.requestId,messageId,SendBird.getInstance().currentUser,this,message,data,customType,_targetLanguages,(new Date).getTime());new UserMessage(msgObj);SendBird.getInstance().sendCommand(cmd,function(ackedCommand,error){if(error)return void callbackWrapper(null,new SendBirdException(error.message,error.code),cb);var userMessage=new UserMessage(ackedCommand.getJsonElement()),me=SendBird.getInstance().currentUser;me&&userMessage._sender&&me.userId==userMessage._sender.userId&&(me.nickname!=userMessage._sender.nickname&&(me.nickname=userMessage._sender.nickname),me.profileUrl!=userMessage._sender.profileUrl&&(me.profileUrl=userMessage._sender.profileUrl)),callbackWrapper(userMessage,null,cb)})},this.updateFileMessage=function(messageId,data,customType,cb){var cmd=Command.bUpdateFileMessage(this.url,messageId,data,customType),msgObj=FileMessage.build(cmd.requestId,messageId,SendBird.getInstance().currentUser,this,"","","","",data,customType,null,null,!1);new FileMessage(msgObj);SendBird.getInstance().sendCommand(cmd,function(ackedCommand,error){if(error)return void callbackWrapper(null,new SendBirdException(error.message,error.code),cb);var fileMessage=new FileMessage(ackedCommand.getJsonElement()),me=SendBird.getInstance().currentUser;me&&fileMessage._sender&&me.userId==fileMessage._sender.userId&&(me.nickname!=fileMessage._sender.nickname&&(me.nickname=fileMessage._sender.nickname),me.profileUrl!=fileMessage._sender.profileUrl&&(me.profileUrl=fileMessage._sender.profileUrl)),callbackWrapper(fileMessage,null,cb)})},this.createMetaCounters=function(metaCounterMap,cb){APIClient.getInstance().createMetaCounters(this.isOpenChannel(),this.url,metaCounterMap,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(response,null,cb)})},this.updateMetaCounters=function(metaCounterMap,upsert,cb){APIClient.getInstance().updateMetaCounters(this.isOpenChannel(),this.url,metaCounterMap,upsert,APIClient.UPDATE_META_COUNTER_MODE_SET,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(response,null,cb)})},this.increaseMetaCounters=function(metaCounterMap,cb){APIClient.getInstance().updateMetaCounters(this.isOpenChannel(),this.url,metaCounterMap,!1,APIClient.UPDATE_META_COUNTER_MODE_INC,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(response,null,cb)})},this.decreaseMetaCounters=function(metaCounterMap,cb){APIClient.getInstance().updateMetaCounters(this.isOpenChannel(),this.url,metaCounterMap,!1,APIClient.UPDATE_META_COUNTER_MODE_DEC,function(response,error){if(error)return void callbackWrapper(null,error,cb);var jsonObject=response,metas={};for(var i in jsonObject){var item=jsonObject[i];metas[i]=item}callbackWrapper(metas,null,cb)})},this.getMetaCounters=function(keys,cb){APIClient.getInstance().getMetaCounters(this.isOpenChannel(),this.url,keys,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(response,null,cb)})},this.getAllMetaCounters=function(cb){APIClient.getInstance().getAllMetaCounters(this.isOpenChannel(),this.url,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(response,null,cb)})},this.deleteMetaCounter=function(key,cb){APIClient.getInstance().deleteMetaCounter(this.isOpenChannel(),this.url,key,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(response,null,cb)})},this.deleteAllMetaCounters=function(cb){APIClient.getInstance().deleteAllMetaCounters(this.isOpenChannel(),this.url,function(response,error){if(error)return void(cb&&callbackWrapper(null,error,cb));callbackWrapper(response,null,cb)})},this.createMetaData=function(metaDataMap,cb){APIClient.getInstance().createMetaData(this.isOpenChannel(),this.url,metaDataMap,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(response,null,cb)})},this.updateMetaData=function(metaDataMap,upsert,cb){APIClient.getInstance().updateMetaData(this.isOpenChannel(),this.url,metaDataMap,upsert,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(response,null,cb)})},this.getMetaData=function(keys,cb){APIClient.getInstance().getMetaData(this.isOpenChannel(),this.url,keys,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(response,null,cb)})},this.getAllMetaData=function(cb){APIClient.getInstance().getAllMetaData(this.isOpenChannel(),this.url,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(response,null,cb)})},this.deleteMetaData=function(key,cb){APIClient.getInstance().deleteMetaData(this.isOpenChannel(),this.url,key,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(response,null,cb)})},this.deleteAllMetaData=function(cb){APIClient.getInstance().deleteAllMetaData(this.isOpenChannel(),this.url,function(response,error){if(error)return void(cb&&callbackWrapper(null,error,cb));callbackWrapper(response,null,cb)})},this.deleteMessage=function(message,cb){var _SELF=this;if(!message)return void callbackWrapper(null,new SendBirdException("Invalid arguments.",SendBirdError.INVALID_PARAMETER),cb);APIClient.getInstance().deleteMessage(_SELF.isOpenChannel(),_SELF.url,message.messageId,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(null,null,cb)})},this.channelType=BaseChannel.CHANNEL_TYPE_BASE,jsonObject&&this._update(jsonObject)};BaseChannel.CHANNEL_TYPE_OPEN="open",BaseChannel.CHANNEL_TYPE_GROUP="group",BaseChannel.CHANNEL_TYPE_BASE="base";var OpenChannel=function(jsonObject){this.parse=function(jsonObject){if(jsonObject.hasOwnProperty("participant_count")&&(this.participantCount=parseInt(jsonObject.participant_count)),jsonObject.hasOwnProperty("operators")&&jsonObject.operators){this.operators=[];for(var i in jsonObject.operators){var operator=new User(jsonObject.operators[i]);this.operators.push(operator)}}},this.refresh=function(cb){OpenChannel.getChannelWithoutCache(this.url,function(channel,error){if(errorFirstCallback){var temp=channel;channel=error,error=temp}if(error)return void callbackWrapper(null,error,cb);callbackWrapper(null,null,cb)})},this.update=function(jsonObject){this._update(jsonObject),this.parse(jsonObject)},this.enter=function(cb){var _SELF=this,cmd=Command.bEnter(_SELF.url);SendBird.getInstance().sendCommand(cmd,function(response,error){if(error)return void callbackWrapper(null,new SendBirdException(error.message,error.code),cb);OpenChannel.enteredChannels[_SELF.url]=_SELF,callbackWrapper(null,null,cb)})},this.exit=function(cb){var _SELF=this,cmd=Command.bExit(_SELF.url);SendBird.getInstance().sendCommand(cmd,function(response,error){if(error)return void callbackWrapper(null,new SendBirdException(error.message,error.code),cb);delete OpenChannel.enteredChannels[_SELF.url],callbackWrapper(null,null,cb)})},this.createParticipantListQuery=function(){return new UserListQuery(UserListQuery.PARTICIPANT,this)},this.createMutedUserListQuery=function(){return new UserListQuery(UserListQuery.MUTED_USER,this)},this.createBannedUserListQuery=function(){return new UserListQuery(UserListQuery.BANNED_USER,this)},this.banUser=function(user,seconds,cb){if(!user||parseInt(seconds)<0)return void callbackWrapper(null,new SendBirdException("Invalid parameter.",SendBirdError.INVALID_PARAMETER),cb);this.banUserWithUserId(user.userId,seconds,cb)},this.banUserWithUserId=function(userId,seconds,cb){if(!userId||parseInt(seconds)<0)return void callbackWrapper(null,new SendBirdException("Invalid parameter.",SendBirdError.INVALID_PARAMETER),cb);APIClient.getInstance().banUser(this.url,userId,null,seconds,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(null,null,cb)})},this.unbanUser=function(user,cb){if(!user)return void callbackWrapper(null,new SendBirdException("Invalid parameter.",SendBirdError.INVALID_PARAMETER),cb);this.unbanUserWithUserId(user.userId,cb)},this.unbanUserWithUserId=function(userId,cb){if(!userId)return void callbackWrapper(null,new SendBirdException("Invalid parameter.",SendBirdError.INVALID_PARAMETER),cb);APIClient.getInstance().unbanUser(this.url,userId,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(null,null,cb)})},this.muteUser=function(user,cb){if(!user)return void callbackWrapper(null,new SendBirdException("Invalid parameter.",SendBirdError.INVALID_PARAMETER),cb);this.muteUserWithUserId(user.userId,cb)},this.muteUserWithUserId=function(userId,cb){if(!userId)return void callbackWrapper(null,new SendBirdException("Invalid parameter.",SendBirdError.INVALID_PARAMETER),cb);APIClient.getInstance().muteUser(this.url,userId,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(null,null,cb)})},this.unmuteUser=function(user,cb){if(!user)return void callbackWrapper(null,new SendBirdException("Invalid parameter.",SendBirdError.INVALID_PARAMETER),cb);this.unmuteUserWithUserId(user.userId,cb)},this.unmuteUserWithUserId=function(userId,cb){if(!userId)return void callbackWrapper(null,new SendBirdException("Invalid parameter.",SendBirdError.INVALID_PARAMETER),cb);APIClient.getInstance().unmuteUser(this.url,userId,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(null,null,cb)})},this.isOperator=function(user){return!!user&&this.isOperatorWithUserId(user.userId)},this.isOperatorWithUserId=function(userId){for(var i in this.operators)if(this.operators[i].userId==userId)return!0;return!1},this.channelType=BaseChannel.CHANNEL_TYPE_OPEN,this.participantCount=0,this.operators=[],jsonObject&&(this._update(jsonObject),this.parse(jsonObject))};_inherit(BaseChannel,OpenChannel),OpenChannel.enteredChannels={},OpenChannel.clearEnteredChannels=function(){OpenChannel.enteredChannels={}},OpenChannel.createOpenChannelListQuery=function(){return new OpenChannelListQuery},OpenChannel.createChannel=function(){var name,coverUrl,data,operatorUserIds,customType,cb;switch(arguments.length){case 1:cb=arguments[0];break;case 4:name=arguments[0],coverUrl=arguments[1],data=arguments[2],cb=arguments[3];break;case 5:name=arguments[0],coverUrl=arguments[1],data=arguments[2],operatorUserIds=arguments[3],cb=arguments[4];break;case 6:name=arguments[0],coverUrl=arguments[1],data=arguments[2],operatorUserIds=arguments[3],customType=arguments[4],cb=arguments[5]}OpenChannel.createChannelWithOperatorUserIds(name,coverUrl,data,operatorUserIds,customType,cb)},OpenChannel.upsert=function(jsonObject){var newChannel=new OpenChannel(jsonObject) -;return OpenChannel.cachedChannels.hasOwnProperty(newChannel.url)?OpenChannel.cachedChannels[newChannel.url].update(jsonObject):OpenChannel.cachedChannels[newChannel.url]=newChannel,OpenChannel.cachedChannels[newChannel.url]},OpenChannel.createChannelWithOperatorUserIds=function(name,coverUrl,data,operatorUserIds,customType,cb){"function"==typeof customType&&(cb=customType,customType=""),APIClient.getInstance().createOpenChannel(name,coverUrl,data,operatorUserIds,customType,function(response,error){if(error)return void callbackWrapper(null,error,cb);var channel=OpenChannel.upsert(response);callbackWrapper(channel,null,cb)})},OpenChannel.cachedChannels={},OpenChannel.clearCache=function(){OpenChannel.cachedChannels={}},OpenChannel.removeCachedChannel=function(channelUrl){delete OpenChannel.cachedChannels[channelUrl]},OpenChannel.getChannel=function(channelUrl,cb){OpenChannel.cachedChannels.hasOwnProperty(channelUrl)?callbackWrapper(OpenChannel.cachedChannels[channelUrl],null,cb):OpenChannel.getChannelWithoutCache(channelUrl,cb)},OpenChannel.getChannelWithoutCache=function(channelUrl,cb){APIClient.getInstance().getOpenChannel(channelUrl,function(response,error){if(error)return void callbackWrapper(null,error,cb);OpenChannel.upsert(response),callbackWrapper(OpenChannel.cachedChannels[channelUrl],null,cb)})};var GroupChannel=function(jsonObject){var startTypingLastSentAt,endTypingLastSentAt,cachedTypingStatus={};this.parse=function(jsonObject){var _SELF=this;if(_SELF.isDistinct=!!jsonObject.is_distinct,_SELF.unreadMessageCount=parseInt(jsonObject.unread_message_count),jsonObject.hasOwnProperty("read_receipt")){_SELF.cachedReadReceiptStatus={};for(var key in jsonObject.read_receipt){var value=jsonObject.read_receipt[key];_SELF.updateReadReceipt(key,parseInt(value))}}if(jsonObject.hasOwnProperty("members")){_SELF.members=[],_SELF.memberMap={};jsonObject.members.forEach(function(member){var user=new User(member);_SELF.members.push(user),_SELF.memberMap[user.userId]=user}),_SELF.memberCount=_SELF.members.length}jsonObject.hasOwnProperty("member_count")&&(_SELF.memberCount=parseInt(jsonObject.member_count)),jsonObject.hasOwnProperty("last_message")&&"object"==typeof jsonObject.last_message&&jsonObject.last_message?_SELF.lastMessage=BaseMessage.build(jsonObject.last_message,_SELF):_SELF.lastMessage=null},this.refresh=function(cb){GroupChannel.getChannelWithoutCache(this.url,function(channel,error){if(errorFirstCallback){var temp=channel;channel=error,error=temp}if(error)return void callbackWrapper(null,error,cb);callbackWrapper(null,null,cb)})},this.update=function(jsonObject){this._update(jsonObject),this.parse(jsonObject)};var userToIds=function(userId){var userIds=[];return userId instanceof User?(userIds=[],userIds.push(userId.userId),userIds):Array.isArray(userId)?(userIds=[],userId.forEach(function(user){user instanceof User&&userIds.push(user.userId),parseInt(user)>0&&userIds.push(user)}),userIds):parseInt(userId)>0?(userIds=[],userIds.push(userId),userIds):void 0};this.invite=function(_users,cb){var userIds=userToIds(_users);this.inviteWithUserIds(userIds,cb)},this.inviteWithUserIds=function(userIds,cb){APIClient.getInstance().groupChannelInvite(this.url,userIds,function(response,error){if(error)return void callbackWrapper(null,error,cb);GroupChannel.upsert(response),callbackWrapper(null,null,cb)})},this.hide=function(cb){APIClient.getInstance().groupChannelHide(this.url,SendBird.getInstance().getCurrentUserId(),function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(response,null,cb)})},this.leave=function(cb){APIClient.getInstance().groupChannelLeave(this.url,SendBird.getInstance().getCurrentUserId(),function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(null,null,cb)})},this.markAsRead=function(){this._sendMarkAsRead(null)},this._sendMarkAsRead=function(cb){var _SELF=this,cmd=Command.bRead(_SELF.url);SendBird.getInstance().sendCommand(cmd,function(ackCommand,error){if(error)return void callbackWrapper(null,new SendBirdException(error.message,error.code),cb);if(_SELF.unreadMessageCount>0){_SELF.unreadMessageCount=0;for(var i in SendBird.getInstance().channelHandlers){SendBird.getInstance().channelHandlers[i].onChannelChanged(_SELF)}}callbackWrapper(null,null,cb)})},this.getReadReceipt=function(message){if(!(message instanceof BaseMessage))return console.log("message is not BaseMessage instance"),-1;if(message.messageType==message.MESSAGE_TYPE_ADMIN)return 0;var me=SendBird.getInstance().currentUser,unreadMemberCount=0,createdAt=message.createdAt,members=this.members;for(var i in members){var member=members[i],key=member.userId;if(!(me.userId==key||message.sender&&message.sender.userId==key)){this.cachedReadReceiptStatus[key]=1e4&&(delete cachedTypingStatus[i],removed=!0)}return removed},this.updateTypingStatus=function(user,start){start?cachedTypingStatus[user.userId]=(new Date).getTime():delete cachedTypingStatus[user.userId]},this.isTyping=function(){return 0!=Object.keys(cachedTypingStatus).length},this.getTypingMembers=function(){var result=[];for(var userId in cachedTypingStatus){var user=this.memberMap[userId];this.memberMap[userId]&&result.push(user)}return result},this.addMember=function(user){this.removeMember(user),this.memberMap[user.userId]=user,this.members.push(user),this.memberCount++,this.updateReadReceipt(user.userId,0)},this.removeMember=function(user){var targetUserId=user.userId;if(this.memberMap.hasOwnProperty(user.userId)){delete this.memberMap[user.userId];for(var i in this.members){if(this.members[i].userId==targetUserId){this.members.splice(i,1);break}}this.memberCount--}},this.setPushPreference=function(pushOn,cb){APIClient.getInstance().setPushPreference(SendBird.getInstance().getCurrentUserId(),this.url,pushOn,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(response,null,cb)})},this.getPushPreference=function(cb){APIClient.getInstance().getPushPreference(SendBird.getInstance().getCurrentUserId(),this.url,function(response,error){if(error)return void callbackWrapper(null,error,cb);if(cb){var pushOn;try{pushOn=response.enable}catch(e){pushOn=!1}callbackWrapper(pushOn,null,cb)}})},this.channelType=BaseChannel.CHANNEL_TYPE_GROUP,this.isDistinct=!1,this.unreadMessageCount=0,this.members=[],this.memberMap={},this.lastMessage={},this.memberCount=0,this.cachedReadReceiptStatus={},jsonObject&&(this._update(jsonObject),this.parse(jsonObject))};_inherit(BaseChannel,GroupChannel),GroupChannel.createMyGroupChannelListQuery=function(){return new GroupChannelListQuery(SendBird.getInstance().currentUser)},GroupChannel.getTotalUnreadMessageCount=function(cb){APIClient.getInstance().getTotalUnreadMessageCount(SendBird.getInstance().getCurrentUserId(),function(response,error){if(error)return void callbackWrapper(null,error,cb);var unreadCount=parseInt(response.unread_count);callbackWrapper(unreadCount,null,cb)})},GroupChannel.getTotalUnreadChannelCount=function(cb){APIClient.getInstance().getTotalUnreadChannelCount(SendBird.getInstance().getCurrentUserId(),function(response,error){if(error)return void callbackWrapper(null,error,cb);var unreadCount=parseInt(response.unread_count);callbackWrapper(unreadCount,null,cb)})},GroupChannel.createChannel=function(){var users=null,isDistinct=null,name=null,coverUrl=null,data=null,callback=null,customType=null;switch(arguments.length){case 3:users=arguments[0],isDistinct=arguments[1],callback=arguments[2];break;case 4:users=arguments[0],isDistinct=arguments[1],customType=arguments[2],callback=arguments[3];break;case 6:users=arguments[0],isDistinct=arguments[1],name=arguments[2],coverUrl=arguments[3],data=arguments[4],callback=arguments[5];break;case 7:users=arguments[0],isDistinct=arguments[1],name=arguments[2],coverUrl=arguments[3],data=arguments[4],customType=arguments[5],callback=arguments[6]}var userIds=[];users.forEach(function(user){userIds.push(user.userId)}),GroupChannel.createChannelWithUserIds(userIds,isDistinct,name,coverUrl,data,customType,callback)},GroupChannel.createChannelWithUserIds=function(_userIds,isDistinct,name,coverUrl,data,customType,cb){"function"==typeof customType&&(cb=customType,customType="");var userIdSet=_userIds.filter(function(elem,index,self){return index==self.indexOf(elem)}),me=SendBird.getInstance().currentUser;userIdSet.push(me.userId),APIClient.getInstance().createGroupChannel(userIdSet,isDistinct,name,coverUrl,data,customType,function(response,error){if(error)return void callbackWrapper(null,error,cb);var channel=new GroupChannel(response);GroupChannel.cachedChannels[channel.url]=channel,callbackWrapper(channel,null,cb)})},GroupChannel.cachedChannels={},GroupChannel.clearCache=function(){GroupChannel.cachedChannels={}},GroupChannel.removeCachedChannel=function(channelUrl){delete GroupChannel.cachedChannels[channelUrl]},GroupChannel.upsert=function(jsonObject){var newChannel=new GroupChannel(jsonObject);return GroupChannel.cachedChannels.hasOwnProperty(newChannel.url)?GroupChannel.cachedChannels[newChannel.url].update(jsonObject):GroupChannel.cachedChannels[newChannel.url]=newChannel,GroupChannel.cachedChannels[newChannel.url]},GroupChannel.getChannelWithoutCache=function(channelUrl,cb){APIClient.getInstance().getGroupChannel(channelUrl,!0,!0,function(response,error){if(error)return void callbackWrapper(null,error,cb);GroupChannel.upsert(response),callbackWrapper(GroupChannel.cachedChannels[channelUrl],null,cb)})},GroupChannel.getChannel=function(channelUrl,cb){GroupChannel.cachedChannels.hasOwnProperty(channelUrl)?callbackWrapper(GroupChannel.cachedChannels[channelUrl],null,cb):GroupChannel.getChannelWithoutCache(channelUrl,cb)},GroupChannel.markAsReadAllLastSentAt,GroupChannel.markAsReadAll=function(cb){var now=(new Date).getTime();if(now-GroupChannel.markAsReadAllLastSentAt<1e3)return void callbackWrapper(null,new SendBirdException("MarkAsRead rate limit exceeded.",SendBirdError.MARK_AS_READ_RATE_LIMIT_EXCEEDED),cb);GroupChannel.markAsReadAllLastSentAt=now,APIClient.getInstance().groupChannelMarkAsReadAll(SendBird.getInstance().getCurrentUserId(),function(response,error){if(error)return void callbackWrapper(null,error,cb);for(var i in GroupChannel.cachedChannels)GroupChannel.cachedChannels[i].unreadMessageCount=0;callbackWrapper(null,null,cb)})};var ChannelEvent=function(jsonObject){jsonObject&&(this.category=jsonObject.hasOwnProperty("cat")?parseInt(jsonObject.cat):0,this.data=jsonObject.hasOwnProperty("data")?jsonObject.data:null,this.channelUrl=jsonObject.hasOwnProperty("channel_url")?String(jsonObject.channel_url):"",this.channelType=jsonObject.hasOwnProperty("channel_type")?String(jsonObject.channel_type):BaseChannel.CHANNEL_TYPE_GROUP),this.isGroupChannel=function(){return this.channelType==BaseChannel.CHANNEL_TYPE_GROUP},this.isOpenChannel=function(){return this.channelType==BaseChannel.CHANNEL_TYPE_OPEN}};ChannelEvent.CATEGORY_NONE=0,ChannelEvent.CATEGORY_CHANNEL_ENTER=10102,ChannelEvent.CATEGORY_CHANNEL_EXIT=10103,ChannelEvent.CATEGORY_USER_CHANNEL_MUTE=10201,ChannelEvent.CATEGORY_USER_CHANNEL_UNMUTE=10200,ChannelEvent.CATEGORY_USER_CHANNEL_BAN=10601,ChannelEvent.CATEGORY_USER_CHANNEL_UNBAN=10600,ChannelEvent.CATEGORY_CHANNEL_FREEZE=10701,ChannelEvent.CATEGORY_CHANNEL_UNFREEZE=10700,ChannelEvent.CATEGORY_TYPING_START=10900,ChannelEvent.CATEGORY_TYPING_END=10901,ChannelEvent.CATEGORY_CHANNEL_JOIN=1e4,ChannelEvent.CATEGORY_CHANNEL_LEAVE=10001,ChannelEvent.CATEGORY_CHANNEL_PROP_CHANGED=11e3,ChannelEvent.CATEGORY_CHANNEL_DELETED=12e3;var ReadStatus=function(jsonObject){jsonObject&&(this.reader=new User(jsonObject.user),this.timestamp=parseInt(jsonObject.ts),this.channelUrl=jsonObject.hasOwnProperty("channel_url")?String(jsonObject.channel_url):"",this.channelType=jsonObject.hasOwnProperty("channel_type")?String(jsonObject.channel_type):BaseChannel.CHANNEL_TYPE_GROUP)},User=function(jsonObject){this.nickname="",this.profileUrl="",this.userId="",this.connectionStatus,this.lastSeenAt=null;var _SELF=this;if(jsonObject)try{jsonObject.hasOwnProperty("guest_id")&&(_SELF.userId=String(jsonObject.guest_id)),jsonObject.hasOwnProperty("user_id")&&(_SELF.userId=String(jsonObject.user_id)),jsonObject.hasOwnProperty("name")&&(_SELF.nickname=String(jsonObject.name)),jsonObject.hasOwnProperty("nickname")&&(_SELF.nickname=String(jsonObject.nickname)),jsonObject.hasOwnProperty("image")&&(_SELF.profileUrl=String(jsonObject.image)),jsonObject.hasOwnProperty("profile_url")&&(_SELF.profileUrl=String(jsonObject.profile_url)),jsonObject.hasOwnProperty("is_online")?_SELF.connectionStatus=jsonObject.is_online?User.ONLINE:User.OFFLINE:_SELF.connectionStatus=User.NON_AVAILABLE,jsonObject.hasOwnProperty("last_seen_at")?_SELF.lastSeenAt=parseInt(jsonObject.last_seen_at):_SELF.lastSeenAt=0}catch(e){console.log(e)}};User.NON_AVAILABLE="nonavailable",User.ONLINE="online",User.OFFLINE="offline",User.build=function(userId,nickname,profileUrl,isOnline,lastSeenAt){return{user_id:userId,nickname:nickname,profile_url:profileUrl,is_online:isOnline,last_seen_at:lastSeenAt}};var Command=function(_command,_payload,_requestId){this.isAckRequired=function(){return"MESG"==this.command||"FILE"==this.command||"ENTR"==this.command||"EXIT"==this.command||"READ"==this.command||"MEDI"==this.command||"FEDI"==this.command},this.encode=function(){return this.command+this.payload+"\n"},this.decode=function(cmd){cmd=cmd.trim(),this.command=cmd.substring(0,4),this.payload=cmd.substring(4)},this.getJsonElement=function(){return JSON.parse(this.payload)},this.isRequestIdCommand=function(){return this.isAckRequired()||"EROR"==this.command},this.command,this.payload,this.requestId;var _SELF=this;if(0!=arguments.length){var reqId;switch(arguments.length){case 1:var data=arguments[0];if(!data||data.length<=4)return _SELF.command="NOOP",void(_SELF.payload="{}");if(data=data.trim(),_SELF.command=data.substring(0,4),_SELF.payload=data.substring(4),_SELF.isRequestIdCommand()){var obj=_SELF.getJsonElement();obj&&(_SELF.requestId=obj.hasOwnProperty("req_id")?obj.req_id:"")}break;case 3:reqId=arguments[2];case 2:var command=arguments[0],payload=arguments[1];reqId=reqId||"",_SELF.command=command,_SELF.requestId=reqId,_SELF.requestId||_SELF.isRequestIdCommand()&&(_SELF.requestId=Command.generateRequestId()),payload.req_id=_SELF.requestId,_SELF.payload=JSON.stringify(payload)}}};Command.bMessage=function(channelUrl,message,data,customType,mentionedUserIds,targetLanguages){var obj={};obj.channel_url=channelUrl,obj.message=message,obj.data=data,obj.mentioned=[];for(var i in mentionedUserIds){var item=mentionedUserIds[i];obj.mentioned.push(String(item))}return customType&&(obj.custom_type=customType),targetLanguages.length>0&&(obj.target_langs=targetLanguages),new Command("MESG",obj)},Command.bRead=function(channelUrl){var obj={};return obj.channel_url=channelUrl,new Command("READ",obj)},Command.bTypeStart=function(channelUrl,time){var obj={};return obj.channel_url=channelUrl,obj.time=time,new Command("TPST",obj)},Command.bTypeEnd=function(channelUrl,time){var obj={};return obj.channel_url=channelUrl,obj.time=time,new Command("TPEN",obj)},Command.bFile=function(requestId,channelUrl,url,name,type,size,data,customType,thumbnails,requireAuth){var obj={};return obj.channel_url=channelUrl,obj.url=url,obj.name=name,obj.type=type,obj.size=size,obj.custom=data,customType&&(obj.custom_type=customType),thumbnails&&(obj.thumbnails=thumbnails),requireAuth&&(obj.require_auth=requireAuth),new Command("FILE",obj,requestId)},Command.bPing=function(){var obj={};return obj.id=(new Date).getTime(),new Command("PING",obj)},Command.bEnter=function(channelUrl){var obj={};return obj.channel_url=channelUrl,new Command("ENTR",obj)},Command.bExit=function(channelUrl){var obj={};return obj.channel_url=channelUrl,new Command("EXIT",obj)},Command.bUpdateUserMessage=function(channelUrl,messageId,message,data,customType){var obj={};return obj.channel_url=channelUrl,obj.msg_id=messageId,null!=message&&message!=undefined&&(obj.message=message),null!=data&&data!=undefined&&(obj.data=data),null!=customType&&customType!=undefined&&(obj.custom_type=customType),new Command("MEDI",obj)},Command.bUpdateFileMessage=function(channelUrl,messageId,data,customType){var obj={};return obj.channel_url=channelUrl,obj.msg_id=messageId,null!=data&&data!=undefined&&(obj.data=data),null!=customType&&customType!=undefined&&(obj.custom_type=customType),new Command("FEDI",obj)},Command.requestIdSeed=(new Date).getTime(),Command.generateRequestId=function(){return Command.requestIdSeed++,String(Command.requestIdSeed)};var GroupChannelListQuery=function(_user){this.isLoading=!1,this.limit=20,this.includeEmpty=!1,this.order=GroupChannelListQuery.ORDER_LATEST_LAST_MESSAGE,this.hasNext=!0,this.userIdsFilter=[],this.userIdsFilterExactMatch=!1,this.nicknameContainsFilter="",this.queryType="AND";var user=_user,token="",sInstance=this;this.next=function(cb){if(!sInstance.hasNext)return void callbackWrapper([],null,cb);sInstance.isLoading&&callbackWrapper(null,new SendBirdException("Query in progress.",SendBirdError.QUERY_IN_PROGRESS),cb),sInstance.isLoading=!0,APIClient.getInstance().loadUserGroupChannelList(user.userId,token,sInstance.limit,sInstance.includeEmpty,sInstance.order,sInstance.userIdsFilter,sInstance.userIdsFilterExactMatch,sInstance.nicknameContainsFilter,sInstance.queryType,function(response,error){if(error)return sInstance.isLoading=!1,void callbackWrapper(null,error,cb);var result=response;(!(token=String(result.next))||token.length<=0)&&(sInstance.hasNext=!1);var channelObjs=result.channels,channels=[];for(var i in channelObjs){var channel=GroupChannel.upsert(channelObjs[i]);channels.push(channel)}sInstance.isLoading=!1,callbackWrapper(channels,null,cb)})}};GroupChannelListQuery.ORDER_LATEST_LAST_MESSAGE="latest_last_message",GroupChannelListQuery.ORDER_CHRONOLOGICAL="chronological";var MessageListQuery=function(_channel){this.isLoading=!1;var channel=_channel,sInstance=this;this.next=function(messageTimestamp,limit,reverse,cb){if(sInstance.isLoading)return void callbackWrapper(null,new SendBirdException("Query in progress.",SendBirdError.QUERY_IN_PROGRESS),cb);sInstance.isLoading=!0,APIClient.getInstance().messageList(channel.isOpenChannel(),channel.url,messageTimestamp,0,limit,!1,reverse,"","",function(response,error){if(error)return sInstance.isLoading=!1,void callbackWrapper(null,error,cb);var objs=response.messages,messages=[];for(var i in objs){var msg=BaseMessage.build(objs[i],channel);msg&&messages.push(msg)}sInstance.isLoading=!1,callbackWrapper(messages,null,cb)})},this.prev=function(messageTimestamp,limit,reverse,cb){if(sInstance.isLoading)return void callbackWrapper(null,new SendBirdException("Query in progress.",SendBirdError.QUERY_IN_PROGRESS),cb);sInstance.isLoading=!0,APIClient.getInstance().messageList(channel.isOpenChannel(),channel.url,messageTimestamp,limit,0,!1,reverse,"","",function(response,error){if(error)return sInstance.isLoading=!1,void callbackWrapper(null,error,cb);var objs=response.messages,messages=[];for(var i in objs){var msg=BaseMessage.build(objs[i],channel);msg&&messages.push(msg)}sInstance.isLoading=!1,callbackWrapper(messages,null,cb)})},this.load=function(messageTimestamp,prevLimit,nextLimit,reverse,cb){if(sInstance.isLoading)return void callbackWrapper(null,new SendBirdException("Query in progress.",SendBirdError.QUERY_IN_PROGRESS),cb);sInstance.isLoading=!0,APIClient.getInstance().messageList(channel.isOpenChannel(),channel.url,messageTimestamp,prevLimit,nextLimit,!0,reverse,"","",function(response,error){if(error)return sInstance.isLoading=!1,void callbackWrapper(null,error,cb);var objs=response.messages,messages=[];for(var i in objs){var msg=BaseMessage.build(objs[i],channel);msg&&messages.push(msg)}sInstance.isLoading=!1,callbackWrapper(messages,null,cb)})}},OpenChannelListQuery=function(){var token="";this.limit=20,this.isLoading=!1,this.hasNext=!0,this.nameKeyword="",this.urlKeyword="";var sInstance=this;this.next=function(cb){return this.hasNext?this.isLoading?void callbackWrapper(null,new SendBirdException("WS connection closed.",SendBirdError.QUERY_IN_PROGRESS),cb):(sInstance.isLoading=!0,void APIClient.getInstance().loadOpenChannelList(token,sInstance.limit,sInstance.nameKeyword,sInstance.urlKeyword,function(response,error){if(error)return sInstance.isLoading=!1,void callbackWrapper(null,error,cb);var result=response;try{token=String(result.next)}catch(e){token=""}token||(sInstance.hasNext=!1);var channelObjs=result.channels,channels=[];channelObjs.forEach(function(item){var channel=OpenChannel.upsert(item);channels.push(channel)}),sInstance.isLoading=!1,callbackWrapper(channels,null,cb)})):void callbackWrapper([],null,cb)}},PreviousMessageListQuery=function(_channel){var channel=_channel,messageTimestamp=0x8000000000000000;this.hasMore=!0,this.isLoading=!1;var sInstance=this;this.load=function(limit,reverse,messageType,cb){if("function"==typeof messageType&&(cb=messageType,messageType=""),messageType==BaseMessage.MESSAGE_TYPE_ADMIN?messageType="ADMM":messageType==BaseMessage.MESSAGE_TYPE_USER&&(messageType="MESG"),messageType=messageType==BaseMessage.MESSAGE_TYPE_FILE?"FILE":"",sInstance.hasMore){if(sInstance.isLoading)return void callbackWrapper(null,new SendBirdException("WS connection closed.",SendBirdError.QUERY_IN_PROGRESS),cb);sInstance.isLoading=!0,APIClient.getInstance().messageList(channel.isOpenChannel(),channel.url,messageTimestamp,limit,0,!1,reverse,messageType,"",function(response,error){if(error)return sInstance.isLoading=!1,void callbackWrapper(null,error,cb);var objs=response.messages,messages=[];for(var i in objs){var msg=BaseMessage.build(objs[i],channel);msg&&(messages.push(msg),msg.createdAt<=messageTimestamp&&(messageTimestamp=msg.createdAt))}(messages.length<=0||messages.length300?_ajaxCall(APIClient.API_ROUTING_URL.replace("%s",appId),{},"GET",{SendBird:API_HEADER_PARAM+appId},function(result,error){if(error)return void cb(null,new SendBirdException("Server is unreachable.",SendBirdError.NETWORK_ROUTING_ERROR));WS_HOST=result.ws_server,API_HOST=result.api_server,sbRouterTimer=now,"function"==typeof cb&&cb({API_HOST:API_HOST,WS_HOST:WS_HOST})}):cb({API_HOST:SendBird.getInstance().getCurrentApiHost(),WS_HOST:SendBird.getInstance().getCurrentWsHost()},null)}};var requestFILE=function(url,form,file,fileType,thumbnailSizes,channelUrl,cb,progressHandler,channelRequestObj,messageReqId){if(!SendBird.getInstance().hasLoggedIn())return void(cb&&cb(null,new SendBirdException("Connection should be made first.",SendBirdError.CONNECTION_REQUIRED)));APIClient.getInstance().checkRouting(function(result,error){if(error)cb(null,new SendBirdException("Request failed.",SendBirdError.REQUEST_FAILED));else{var request=_Xhr?new _Xhr:new XMLHttpRequest;request.open("POST",result.API_HOST+url,!0),request.setRequestHeader("SendBird",API_HEADER_PARAM+appId),request.setRequestHeader("Session-Key",APIClient.getInstance().sessionKey);var formData=_FormData?new _FormData:new FormData;fileType&&"undefined"!=typeof Blob?formData.append("file",new Blob([file],{type:fileType}),file.name):formData.append("file",file,file.name), -channelUrl&&formData.append("channel_url",channelUrl);for(var i in thumbnailSizes){var i2=parseInt(i)+1;formData.append("thumbnail"+i2,thumbnailSizes[i].maxWidth+","+thumbnailSizes[i].maxHeight)}request.onload=function(){channelRequestObj&&channelRequestObj[messageReqId]&&delete channelRequestObj[messageReqId];request.status>=200&&request.status<400?_cb_wrapper(null,JSON.parse(request.responseText),cb):_cb_wrapper({status:request.status,statusText:request.statusText,response:request.responseText},null,cb)},request.onerror=function(e){channelRequestObj&&channelRequestObj[messageReqId]&&delete channelRequestObj[messageReqId],cb(null,new SendBirdException(request.statusText,SendBirdError.REQUEST_FAILED))},request.onabort=function(e){channelRequestObj&&channelRequestObj[messageReqId]&&delete channelRequestObj[messageReqId],cb(null,new SendBirdException("File upload has been cancelled.",SendBirdError.REQUEST_CANCELLED))},request.upload.onprogress=function(e){e.lengthComputable&&e.loaded>=e.total&&channelRequestObj&&channelRequestObj[messageReqId]&&delete channelRequestObj[messageReqId],progressHandler&&progressHandler(e)},formData.oldIE?(request.setRequestHeader("Content-Type","multipart/form-data; boundary="+formData.boundary),request.send(formData.toString())):request.send(formData),channelRequestObj&&(channelRequestObj[messageReqId]=request)}})},requestDELETE=function(url,params,cb){if("function"==typeof params&&(cb=params,params={}),!SendBird.getInstance().hasLoggedIn())return void(cb&&cb(null,new SendBirdException("Connection should be made first.",SendBirdError.CONNECTION_REQUIRED)));APIClient.getInstance().checkRouting(function(result,error){error?cb(null,new SendBirdException("Request failed.",SendBirdError.REQUEST_FAILED)):_ajaxCall(result.API_HOST+url,params,"DELETE",{"Session-Key":APIClient.getInstance().sessionKey,SendBird:API_HEADER_PARAM+appId},cb)})},encodeParams=function(params){var encodedParams="";for(var i in params){encodedParams+=encodeURIComponent(params[i])+","}return encodedParams.length>1&&(encodedParams=encodedParams.substring(0,encodedParams.length-1)),encodedParams},requestGET=function(url,params,cb){if("function"==typeof params&&(cb=params,params={}),!SendBird.getInstance().hasLoggedIn())return void(cb&&cb(null,new SendBirdException("Connection should be made first.",SendBirdError.CONNECTION_REQUIRED)));var fullUrl,urlParams="";if(params){for(var key in params)""!=urlParams&&(urlParams+="&"),urlParams+=key+"="+params[key];fullUrl=url+"?"+urlParams}else fullUrl=url;APIClient.getInstance().checkRouting(function(result,error){error?cb(null,new SendBirdException("Request failed.",SendBirdError.REQUEST_FAILED)):_ajaxCall(result.API_HOST+fullUrl,params,"GET",{"Session-Key":APIClient.getInstance().sessionKey,SendBird:API_HEADER_PARAM+appId},cb)})},requestPOST=function(url,params,cb){if("function"==typeof params&&(cb=params,params={}),!SendBird.getInstance().hasLoggedIn())return void(cb&&cb(null,new SendBirdException("Connection should be made first.",SendBirdError.CONNECTION_REQUIRED)));APIClient.getInstance().checkRouting(function(result,error){error?cb(null,error):_ajaxCall(result.API_HOST+url,params,"POST",{"Session-Key":APIClient.getInstance().sessionKey,SendBird:API_HEADER_PARAM+appId},cb)})},requestPUT=function(url,params,cb){if("function"==typeof params&&(cb=params,params={}),!SendBird.getInstance().hasLoggedIn())return void(cb&&cb(null,new SendBirdException("Connection should be made first.",SendBirdError.CONNECTION_REQUIRED)));APIClient.getInstance().checkRouting(function(result,error){error||_ajaxCall(result.API_HOST+url,params,"PUT",{"Session-Key":APIClient.getInstance().sessionKey,SendBird:API_HEADER_PARAM+appId},cb)})};this.groupChannelInvite=function(channelUrl,_userIds,cb){var url=APIClient.API_GROUPCHANNELS_CHANNELURL_INVITE.replace("%s",encodeURIComponent(channelUrl)),form={},userIds=[];try{Array.isArray(_userIds)?userIds=_userIds:userIds.push(_userIds)}catch(e){cb(null,new SendBirdException("Invalid parameter.",SendBirdError.INVALID_PARAMETER))}form.user_ids=userIds,requestPOST(url,form,cb)},this.groupChannelHide=function(channelUrl,userId,cb){var url=APIClient.API_GROUPCHANNELS_CHANNELURL_HIDE.replace("%s",encodeURIComponent(channelUrl)),form={};form.user_id=userId,requestPUT(url,form,cb)},this.groupChannelLeave=function(channelUrl,userId,cb){var url=APIClient.API_GROUPCHANNELS_CHANNELURL_LEAVE.replace("%s",encodeURIComponent(channelUrl)),form={};form.user_id=userId,requestPUT(url,form,cb)},this.groupChannelMarkAsRead=function(channelUrl,userId,cb){var url=APIClient.API_GROUPCHANNELS_CHANNELURL_MESSAGES_MARKASREAD.replace("%s",encodeURIComponent(channelUrl)),form={};form.user_id=userId,requestPUT(url,form,cb)},this.groupChannelMarkAsReadAll=function(userId,cb){var url=APIClient.API_USERS_USERID_MARKASREADALL.replace("%s",encodeURIComponent(userId));requestPUT(url,{},cb)},this.messageList=function(isOpenChannel,channelUrl,messageTimestamp,prevLimit,nextLimit,include,reverse,messageType,customType,cb){var url;url=isOpenChannel?String(APIClient.API_OPENCHANNELS_CHANNELURL_MESSAGES.replace("%s",channelUrl)):String(APIClient.API_GROUPCHANNELS_CHANNELURL_MESSAGES.replace("%s",channelUrl));var params={};params.is_sdk=String(!0),params.message_ts=String(messageTimestamp),params.prev_limit=String(prevLimit),params.next_limit=String(nextLimit),params.include=String(include),params.reverse=String(reverse),messageType&&(params.message_type=String(messageType)),customType&&(params.custom_type=String(customType)),requestGET(url,params,cb)},this.messageListByID=function(isOpenChannel,channelUrl,messageID,prevLimit,nextLimit,include,reverse,messageType,customType,cb){var url;url=isOpenChannel?String(APIClient.API_OPENCHANNELS_CHANNELURL_MESSAGES.replace("%s",channelUrl)):String(APIClient.API_GROUPCHANNELS_CHANNELURL_MESSAGES.replace("%s",channelUrl));var params={};params.is_sdk=String(!0),params.message_id=messageID,params.prev_limit=String(prevLimit),params.next_limit=String(nextLimit),params.include=String(include),params.reverse=String(reverse),messageType&&(params.message_type=String(messageType)),customType&&(params.custom_type=String(customType)),requestGET(url,params,cb)},this.login=function(userId,accessToken,cb){var url=APIClient.API_USERS_USERID_LOGIN.replace("%s",encodeURIComponent(userId)),form={};form.app_id=appId,accessToken&&(form.access_token=accessToken),requestPOST(url,form,function(response,error){error?cb(null,error):(APIClient.getInstance().sessionKey=response.key,APIClient.getInstance().ekey=response.ekey,cb(response,error))})},this.updateUserInfo=function(userId,nickname,profileUrl,cb){var form={};nickname&&(form.nickname=nickname),profileUrl&&(form.profile_url=profileUrl);var url=String(APIClient.API_USERS_USERID).replace("%s",encodeURIComponent(userId));requestPUT(url,form,cb)},this.getGroupChannel=function(channelUrl,member,readReceipt,cb){var url=APIClient.API_GROUPCHANNELS_CHANNELURL.replace("%s",encodeURIComponent(channelUrl)),params={member:String(member),read_receipt:String(readReceipt)};requestGET(url,params,cb)},this.getOpenChannel=function(channelUrl,cb){var url=APIClient.API_OPENCHANNELS_CHANNELURL.replace("%s",encodeURIComponent(channelUrl));requestGET(url,cb)},this.createGroupChannel=function(_userIds,isDistinct,name,coverUrlOrFile,data,customType,cb){var url=APIClient.API_GROUPCHANNELS,userIds=[];"string"==typeof _userIds?userIds.push(_userIds):_userIds.forEach(function(userId){userIds.push(userId)});var form;coverUrlOrFile&&"string"!=typeof coverUrlOrFile?(form=_FormData?new _FormData:new FormData,coverUrlOrFile&&form.append("cover_file",coverUrlOrFile,coverUrlOrFile.name),form.append("user_ids",userIds),form.append("is_distinct",isDistinct),name&&form.append("name",name),data&&form.append("data",data),customType&&form.append("custom_type",customType)):(form={},coverUrlOrFile&&(form.cover_url=coverUrlOrFile),form.user_ids=userIds,form.is_distinct=isDistinct,name&&(form.name=name),data&&(form.data=data),customType&&(form.custom_type=customType)),requestPOST(url,form,cb)},this.createOpenChannel=function(name,coverUrlOrFile,data,operatorIds,customType,cb){var form,url=String(APIClient.API_OPENCHANNELS);coverUrlOrFile&&"string"!=typeof coverUrlOrFile?(form=_FormData?new _FormData:new FormData,coverUrlOrFile&&form.append("cover_file",coverUrlOrFile,coverUrlOrFile.name),name&&form.append("name",name),data&&form.append("data",data),operatorIds&&(Array.isArray(operatorIds)?form.append("operators",operatorIds):form.append("operators",[operatorIds])),customType&&form.append("custom_type",customType)):(form={},coverUrlOrFile&&(form.cover_url=coverUrlOrFile),name&&(form.name=name),data&&(form.data=data),operatorIds&&(Array.isArray(operatorIds)?form.operators=operatorIds:form.operators=[operatorIds]),customType&&(form.custom_type=customType)),requestPOST(url,form,cb)},this.createMetaCounters=function(isOpenChannel,channelUrl,metaCounterMap,cb){var url;url=isOpenChannel?APIClient.API_OPENCHANNELS_CHANNELURL_METACOUNTER.replace("%s",encodeURIComponent(channelUrl)):APIClient.API_GROUPCHANNELS_CHANNELURL_METACOUNTER.replace("%s",encodeURIComponent(channelUrl));var form={};form.metacounter=metaCounterMap,requestPOST(url,form,cb)},this.updateMetaCounters=function(isOpenChannel,channelUrl,metaCounterMap,upsert,mode,cb){var url;url=isOpenChannel?APIClient.API_OPENCHANNELS_CHANNELURL_METACOUNTER.replace("%s",encodeURIComponent(channelUrl)):APIClient.API_GROUPCHANNELS_CHANNELURL_METACOUNTER.replace("%s",encodeURIComponent(channelUrl));var form={};switch(form.metacounter=metaCounterMap,form.upsert=upsert,mode){case APIClient.UPDATE_META_COUNTER_MODE_SET:form.mode="set";break;case APIClient.UPDATE_META_COUNTER_MODE_INC:form.mode="increase";break;case APIClient.UPDATE_META_COUNTER_MODE_DEC:form.mode="decrease"}requestPUT(url,form,cb)},this.getAllMetaCounters=function(isOpenChannel,channelUrl,cb){this.getMetaCounters(isOpenChannel,channelUrl,{},cb)},this.getMetaCounters=function(isOpenChannel,channelUrl,keys,cb){var url;url=isOpenChannel?APIClient.API_OPENCHANNELS_CHANNELURL_METACOUNTER.replace("%s",encodeURIComponent(channelUrl)):APIClient.API_GROUPCHANNELS_CHANNELURL_METACOUNTER.replace("%s",encodeURIComponent(channelUrl));var joinedKeys=encodeParams(keys);requestGET(url,{keys:joinedKeys},cb)},this.deleteMetaCounter=function(isOpenChannel,channelUrl,key,cb){var url="";url=isOpenChannel?APIClient.API_OPENCHANNELS_CHANNELURL_METACOUNTER_KEY.replace("%s",encodeURIComponent(channelUrl)).replace("%s",key):APIClient.API_GROUPCHANNELS_CHANNELURL_METACOUNTER_KEY.replace("%s",encodeURIComponent(channelUrl)).replace("%s",key),requestDELETE(url,{},cb)},this.deleteAllMetaCounters=function(isOpenChannel,channelUrl,cb){var url="";url=isOpenChannel?APIClient.API_OPENCHANNELS_CHANNELURL_METACOUNTER.replace("%s",encodeURIComponent(channelUrl)):APIClient.API_GROUPCHANNELS_CHANNELURL_METACOUNTER.replace("%s",encodeURIComponent(channelUrl)),requestDELETE(url,{},cb)},this.createMetaData=function(isOpenChannel,channelUrl,metaDataMap,cb){var url="";url=isOpenChannel?APIClient.API_OPENCHANNELS_CHANNELURL_METADATA.replace("%s",encodeURIComponent(channelUrl)):APIClient.API_GROUPCHANNELS_CHANNELURL_METADATA.replace("%s",encodeURIComponent(channelUrl));var form={},metas={};for(var i in metaDataMap){var item=metaDataMap[i];metas[i]=item}form.metadata=metas,requestPOST(url,form,cb)},this.updateMetaData=function(isOpenChannel,channelUrl,metaDataMap,upsert,cb){var url="";url=isOpenChannel?APIClient.API_OPENCHANNELS_CHANNELURL_METADATA.replace("%s",encodeURIComponent(channelUrl)):APIClient.API_GROUPCHANNELS_CHANNELURL_METADATA.replace("%s",encodeURIComponent(channelUrl));var form={},metas={};for(var i in metaDataMap){var item=metaDataMap[i];metas[i]=item}form.metadata=metas,form.upsert=upsert,requestPUT(url,form,cb)},this.getAllMetaData=function(isOpenChannel,channelUrl,cb){this.getMetaData(isOpenChannel,channelUrl,{},cb)},this.getMetaData=function(isOpenChannel,channelUrl,keys,cb){var url="";url=isOpenChannel?APIClient.API_OPENCHANNELS_CHANNELURL_METADATA.replace("%s",encodeURIComponent(channelUrl)):APIClient.API_GROUPCHANNELS_CHANNELURL_METADATA.replace("%s",encodeURIComponent(channelUrl));var joinedKeys=encodeParams(keys);requestGET(url,{keys:joinedKeys},cb)},this.deleteMetaData=function(isOpenChannel,channelUrl,key,cb){var url="";url=isOpenChannel?APIClient.API_OPENCHANNELS_CHANNELURL_METADATA_KEY.replace("%s",encodeURIComponent(channelUrl)).replace("%s",key):APIClient.API_GROUPCHANNELS_CHANNELURL_METADATA_KEY.replace("%s",encodeURIComponent(channelUrl)).replace("%s",key),requestDELETE(url,{},cb)},this.deleteAllMetaData=function(isOpenChannel,channelUrl,cb){var url="";url=isOpenChannel?APIClient.API_OPENCHANNELS_CHANNELURL_METADATA.replace("%s",encodeURIComponent(channelUrl)):APIClient.API_GROUPCHANNELS_CHANNELURL_METADATA.replace("%s",encodeURIComponent(channelUrl)),requestDELETE(url,{},cb)},this.loadUserList=function(token,limit,userIds,cb){var url=APIClient.API_USERS,params={token:encodeURIComponent(token),limit:String(limit)};if("function"==typeof userIds)cb=userIds;else try{var serializedUserIds="";for(var i in userIds){serializedUserIds+=userIds[i]+","}serializedUserIds.length>1&&(serializedUserIds=serializedUserIds.substring(0,serializedUserIds.length-1)),params.user_ids=serializedUserIds}catch(e){}requestGET(url,params,cb)},this.loadBlockedUserList=function(blockerUserId,token,limit,cb){var url=APIClient.API_USERS_USERID_BLOCK.replace("%s",encodeURIComponent(blockerUserId)),params={token:encodeURIComponent(token),limit:String(limit)};requestGET(url,params,cb)},this.loadOpenChannelList=function(token,limit,nameKeyword,urlKeyword,cb){var url=APIClient.API_OPENCHANNELS,params={token:encodeURIComponent(token),limit:String(limit)};nameKeyword&&(params.name_contains=encodeURIComponent(nameKeyword)),urlKeyword&&(params.url_contains=encodeURIComponent(urlKeyword)),requestGET(url,params,cb)},this.uploadFile=function(file,fileType,thumbnailSizes,channelUrl,cb,progressHandler,channelRequestObj,messageReqId){requestFILE(APIClient.API_STORAGE_FILE,0,file,fileType,thumbnailSizes,channelUrl,cb,progressHandler,channelRequestObj,messageReqId)},this.uploadProfileImage=function(file,cb){requestFILE(APIClient.API_STORAGE_PROFILE,0,file,"",[],"",cb)},this.loadUserGroupChannelList=function(userId,token,limit,includeEmpty,order,userIds,userIdsExactMatch,nicknameContainsFilter,queryType,cb){var url=APIClient.API_MYGROUPCHANNELS.replace("%s",encodeURIComponent(userId)),params={token:encodeURIComponent(token),limit:String(limit),show_member:!0,show_read_receipt:!0,show_empty:String(includeEmpty),order:order};if(nicknameContainsFilter)try{params.members_nickname_contains=encodeURIComponent(nicknameContainsFilter)}catch(e){}if(userIds.length>0)try{userIdsExactMatch?params.members_exactly_in=encodeParams(userIds):(params.members_include_in=encodeParams(userIds),params.query_type=queryType)}catch(e){}requestGET(url,params,cb)},this.loadOpenChannelParticipantList=function(channelUrl,token,limit,cb){var url=APIClient.API_OPENCHANNELS_CHANNELURL_PARTICIPANTS.replace("%s",channelUrl),params={token:encodeURIComponent(token),limit:String(limit)};requestGET(url,params,cb)},this.loadOpenChannelMutedList=function(channelUrl,token,limit,cb){var url=APIClient.API_OPENCHANNELS_CHANNELURL_MUTE.replace("%s",channelUrl),params={token:encodeURIComponent(token),limit:String(limit)};requestGET(url,params,cb)},this.loadOpenChannelBanList=function(channelUrl,token,limit,cb){var url=APIClient.API_OPENCHANNELS_CHANNELURL_BAN.replace("%s",channelUrl),params={token:encodeURIComponent(token),limit:String(limit)};requestGET(url,params,cb)},this.setPushTemplate=function(userId,templateName,cb){var url=APIClient.API_USERS_USERID_PUSH_TEMPLATE.replace("%s",encodeURIComponent(userId));requestPUT(url,{name:templateName},cb)},this.getPushTemplate=function(userId,cb){var url=APIClient.API_USERS_USERID_PUSH_TEMPLATE.replace("%s",encodeURIComponent(userId));requestGET(url,cb)},this.setDoNotDisturb=function(userId,doNotDisturbOn,startHour,startMin,endHour,endMin,timezone,cb){var url=APIClient.API_USERS_USERID_PUSHPREFERENCE.replace("%s",encodeURIComponent(userId));requestPUT(url,{do_not_disturb:doNotDisturbOn,start_hour:startHour,start_min:startMin,end_hour:endHour,end_min:endMin,timezone:timezone},cb)},this.getDoNotDisturb=function(userId,cb){var url=APIClient.API_USERS_USERID_PUSHPREFERENCE.replace("%s",encodeURIComponent(userId));requestGET(url,cb)},this.setPushPreference=function(userId,channelUrl,value,cb){var url=APIClient.API_USERS_USERID_PUSHPREFERENCE_CHANNELURL.replace("%s",encodeURIComponent(userId)).replace("%s",encodeURIComponent(channelUrl)),params={};params.enable=value,requestPUT(url,params,cb)},this.getPushPreference=function(userId,channelUrl,cb){var url=APIClient.API_USERS_USERID_PUSHPREFERENCE_CHANNELURL.replace("%s",encodeURIComponent(userId)).replace("%s",encodeURIComponent(channelUrl));requestGET(url,cb)},this.registerGCMPushToken=function(userId,token,cb){var url=APIClient.API_USERS_USERID_PUSH_GCM.replace("%s",encodeURIComponent(userId));requestPOST(url,{gcm_reg_token:token},cb)},this.unregisterGCMPushToken=function(userId,token,cb){var url=APIClient.API_USERS_USERID_PUSH_GCM_TOKEN.replace("%s",encodeURIComponent(userId)).replace("%s",encodeURIComponent(token));requestDELETE(url,cb)},this.unregisterGCMPushTokenAll=function(userId,cb){var url=APIClient.API_USERS_USERID_PUSH_GCM.replace("%s",encodeURIComponent(userId));requestDELETE(url,cb)},this.registerAPNSPushToken=function(userId,token,cb){var url=APIClient.API_USERS_USERID_PUSH_APNS.replace("%s",encodeURIComponent(userId));requestPOST(url,{apns_device_token:token},cb)},this.unregisterAPNSPushToken=function(userId,token,cb){var url=APIClient.API_USERS_USERID_PUSH_APNS_TOKEN.replace("%s",encodeURIComponent(userId)).replace("%s",encodeURIComponent(token));requestDELETE(url,cb)},this.unregisterAPNSPushTokenAll=function(userId,cb){var url=APIClient.API_USERS_USERID_PUSH_APNS.replace("%s",encodeURIComponent(userId));requestDELETE(url,cb)},this.unregisterPushTokenAll=function(userId,cb){var url=APIClient.API_USERS_USERID_PUSH.replace("%s",encodeURIComponent(userId));requestDELETE(url,cb)},this.blockUser=function(blockerUserId,blockeeUserId,cb){var url=APIClient.API_USERS_USERID_BLOCK.replace("%s",encodeURIComponent(blockerUserId));requestPOST(url,{target_id:blockeeUserId},cb)},this.unblockUser=function(blockerUserId,blockeeUserId,cb){var url=APIClient.API_USERS_USERID_BLOCK_TARGETID.replace("%s",encodeURIComponent(blockerUserId)).replace("%s",encodeURIComponent(blockeeUserId));requestDELETE(url,{},cb)},this.banUser=function(channelUrl,userId,description,seconds,cb){var url=APIClient.API_OPENCHANNELS_CHANNELURL_BAN.replace("%s",encodeURIComponent(channelUrl)),params={user_id:userId};description&&(params.description=description),params.seconds=String(seconds),requestPOST(url,params,cb)},this.unbanUser=function(channelUrl,userId,cb){var url=APIClient.API_OPENCHANNELS_CHANNELURL_BAN_USERID.replace("%s",encodeURIComponent(channelUrl)).replace("%s",encodeURIComponent(userId));requestDELETE(url,{},cb)},this.muteUser=function(channelUrl,userId,cb){var url=APIClient.API_OPENCHANNELS_CHANNELURL_MUTE.replace("%s",encodeURIComponent(channelUrl));requestPOST(url,{user_id:userId},cb)},this.unmuteUser=function(channelUrl,userId,cb){var url=APIClient.API_OPENCHANNELS_CHANNELURL_MUTE_USERID.replace("%s",encodeURIComponent(channelUrl)).replace("%s",encodeURIComponent(userId));requestDELETE(url,{},cb)},this.deleteMessage=function(isOpenChannel,channelUrl,messageId,cb){var url="";url=isOpenChannel?APIClient.API_OPENCHANNELS_CHANNELURL_MESSAGES_MESSAGEID.replace("%s",encodeURIComponent(channelUrl)).replace("%s",encodeURIComponent(messageId)):APIClient.API_GROUPCHANNELS_CHANNELURL_MESSAGES_MESSAGEID.replace("%s",encodeURIComponent(channelUrl)).replace("%s",encodeURIComponent(messageId)),requestDELETE(url,{},cb)}},apiClientInstance=null;APIClient.getInstance=function(){return null===apiClientInstance?null:apiClientInstance},APIClient.API_VERSION="v3",APIClient.API_ROUTING_URL="https://api-p.sendbird.com/routing/%s",APIClient.API_USERS="/%v/users".replace("%v",APIClient.API_VERSION),APIClient.API_USERS_USERID_LOGIN="/%v/users/%s/login".replace("%v",APIClient.API_VERSION),APIClient.API_USERS_USERID="/%v/users/%s".replace("%v",APIClient.API_VERSION),APIClient.API_USERS_USERID_UNREAD_MESSAGE_COUNT="/%v/users/%s/unread_message_count".replace("%v",APIClient.API_VERSION),APIClient.API_USERS_USERID_UNREAD_CHANNEL_COUNT="/%v/users/%s/unread_channel_count".replace("%v",APIClient.API_VERSION),APIClient.API_USERS_USERID_MARKASREADALL="/%v/users/%s/mark_as_read_all".replace("%v",APIClient.API_VERSION),APIClient.API_USERS_USERID_PUSH_GCM_TOKEN="/%v/users/%s/push/gcm/%s".replace("%v",APIClient.API_VERSION),APIClient.API_USERS_USERID_PUSH_GCM="/%v/users/%s/push/gcm".replace("%v",APIClient.API_VERSION),APIClient.API_USERS_USERID_PUSHPREFERENCE_CHANNELURL="/%v/users/%s/push_preference/%s".replace("%v",APIClient.API_VERSION),APIClient.API_USERS_USERID_PUSHPREFERENCE="/%v/users/%s/push_preference/".replace("%v",APIClient.API_VERSION),APIClient.API_USERS_USERID_PUSH_TEMPLATE="/%v/users/%s/push/template".replace("%v",APIClient.API_VERSION),APIClient.API_USERS_USERID_BLOCK="/%v/users/%s/block".replace("%v",APIClient.API_VERSION),APIClient.API_USERS_USERID_BLOCK_TARGETID="/%v/users/%s/block/%s".replace("%v",APIClient.API_VERSION),APIClient.API_USERS_USERID_PUSH_APNS_TOKEN="/%v/users/%s/push/apns/%s".replace("%v",APIClient.API_VERSION),APIClient.API_USERS_USERID_PUSH_APNS="/%v/users/%s/push/apns".replace("%v",APIClient.API_VERSION),APIClient.API_USERS_USERID_PUSH="/%v/users/%s/push".replace("%v",APIClient.API_VERSION),APIClient.API_OPENCHANNELS="/%v/open_channels".replace("%v",APIClient.API_VERSION),APIClient.API_OPENCHANNELS_CHANNELURL="/%v/open_channels/%s".replace("%v",APIClient.API_VERSION),APIClient.API_OPENCHANNELS_CHANNELURL_MESSAGES="/%v/open_channels/%s/messages".replace("%v",APIClient.API_VERSION),APIClient.API_OPENCHANNELS_CHANNELURL_MESSAGES_MESSAGEID="/%v/open_channels/%s/messages/%s".replace("%v",APIClient.API_VERSION),APIClient.API_OPENCHANNELS_CHANNELURL_PARTICIPANTS="/%v/open_channels/%s/participants".replace("%v",APIClient.API_VERSION),APIClient.API_OPENCHANNELS_CHANNELURL_METADATA="/%v/open_channels/%s/metadata".replace("%v",APIClient.API_VERSION),APIClient.API_OPENCHANNELS_CHANNELURL_METADATA_KEY="/%v/open_channels/%s/metadata/%s".replace("%v",APIClient.API_VERSION),APIClient.API_OPENCHANNELS_CHANNELURL_METACOUNTER="/%v/open_channels/%s/metacounter".replace("%v",APIClient.API_VERSION),APIClient.API_OPENCHANNELS_CHANNELURL_METACOUNTER_KEY="/%v/open_channels/%s/metacounter/%s".replace("%v",APIClient.API_VERSION),APIClient.API_OPENCHANNELS_CHANNELURL_BAN="/%v/open_channels/%s/ban".replace("%v",APIClient.API_VERSION),APIClient.API_OPENCHANNELS_CHANNELURL_BAN_USERID="/%v/open_channels/%s/ban/%s".replace("%v",APIClient.API_VERSION),APIClient.API_OPENCHANNELS_CHANNELURL_MUTE="/%v/open_channels/%s/mute".replace("%v",APIClient.API_VERSION),APIClient.API_OPENCHANNELS_CHANNELURL_MUTE_USERID="/%v/open_channels/%s/mute/%s".replace("%v",APIClient.API_VERSION),APIClient.API_GROUPCHANNELS="/%v/group_channels".replace("%v",APIClient.API_VERSION),APIClient.API_MYGROUPCHANNELS="/%v/users/%s/my_group_channels".replace("%v",APIClient.API_VERSION),APIClient.API_GROUPCHANNELS_CHANNELURL="/%v/group_channels/%s".replace("%v",APIClient.API_VERSION),APIClient.API_GROUPCHANNELS_CHANNELURL_INVITE="/%v/group_channels/%s/invite".replace("%v",APIClient.API_VERSION),APIClient.API_GROUPCHANNELS_CHANNELURL_HIDE="/%v/group_channels/%s/hide".replace("%v",APIClient.API_VERSION),APIClient.API_GROUPCHANNELS_CHANNELURL_LEAVE="/%v/group_channels/%s/leave".replace("%v",APIClient.API_VERSION),APIClient.API_GROUPCHANNELS_CHANNELURL_MESSAGES="/%v/group_channels/%s/messages".replace("%v",APIClient.API_VERSION),APIClient.API_GROUPCHANNELS_CHANNELURL_MESSAGES_MARKASREAD="/%v/group_channels/%s/messages/mark_as_read".replace("%v",APIClient.API_VERSION),APIClient.API_GROUPCHANNELS_CHANNELURL_MESSAGES_TOTALCOUNT="/%v/group_channels/%s/messages/total_count".replace("%v",APIClient.API_VERSION),APIClient.API_GROUPCHANNELS_CHANNELURL_MESSAGES_UNREADCOUNT="/%v/group_channels/%s/messages/unread_count".replace("%v",APIClient.API_VERSION),APIClient.API_GROUPCHANNELS_CHANNELURL_MESSAGES_MESSAGEID="/%v/group_channels/%s/messages/%s".replace("%v",APIClient.API_VERSION),APIClient.API_GROUPCHANNELS_CHANNELURL_MEMBERS="/%v/group_channels/%s/members".replace("%v",APIClient.API_VERSION),APIClient.API_GROUPCHANNELS_CHANNELURL_METADATA="/%v/group_channels/%s/metadata".replace("%v",APIClient.API_VERSION),APIClient.API_GROUPCHANNELS_CHANNELURL_METADATA_KEY="/%v/group_channels/%s/metadata/%s".replace("%v",APIClient.API_VERSION),APIClient.API_GROUPCHANNELS_CHANNELURL_METACOUNTER="/%v/group_channels/%s/metacounter".replace("%v",APIClient.API_VERSION),APIClient.API_GROUPCHANNELS_CHANNELURL_METACOUNTER_KEY="/%v/group_channels/%s/metacounter/%s".replace("%v",APIClient.API_VERSION),APIClient.API_STORAGE_FILE="/%v/storage/file".replace("%v",APIClient.API_VERSION),APIClient.API_STORAGE_PROFILE="/%v/storage/profile_image".replace("%v",APIClient.API_VERSION),APIClient.UPDATE_META_COUNTER_MODE_SET=0,APIClient.UPDATE_META_COUNTER_MODE_INC=1,APIClient.UPDATE_META_COUNTER_MODE_DEC=2;var SendBird=function(_initParams){var _singleton=SendBird.getInstance();if(_singleton)return _singleton;try{if(!_initParams.hasOwnProperty("appId"))return console.log("Must be set appId"),{}}catch(e){return console.log("Must be set appId"),{}}this.GCMPushToken="",this.APNSPushToken="",this.PUSH_TEMPLATE_DEFAULT="default",this.PUSH_TEMPLATE_ALTERNATIVE="alternative",this.pushTokenRegistrationState={SUCCESS:"success",PENDING:"pending",ERROR:"error"},this.loginTimer,this.onLoginTimerCancel,this.globalTimer,this.reconnectTimer,this.onReconnectTimerCancel,this.currentUser=null,this.getCurrentUserId=function(){return SendBird.getInstance().currentUser?SendBird.getInstance().currentUser.userId:null},this.wsClient,this.connectionState={CONNECTING:"CONNECTING",OPEN:"OPEN",CLOSING:"CLOSING",CLOSED:"CLOSED"},this.ConnectionState=this.connectionState,this.OpenChannel=OpenChannel,this.GroupChannel=GroupChannel,this.UserMessage=UserMessage,this.channelHandlers={},this.connectionHandlers={};var ackStateMap={};appId=_initParams.appId,sendbirdInstance=this,apiClientInstance=APIClient.getInstance(),apiClientInstance||(apiClientInstance=new APIClient),this.Options={UseMemberAsMessageSender:!1},this.customApiHost=null,this.customWsHost=null,this.ChannelHandler=function(){this.onMessageReceived=function(channel,message){},this.onMessageUpdated=function(channel,message){},this.onMessageDeleted=function(channel,msgId){},this.onReadReceiptUpdated=function(channel){},this.onTypingStatusUpdated=function(channel){},this.onUserJoined=function(channel,user){},this.onUserLeft=function(channel,user){},this.onUserEntered=function(channel,user){},this.onUserExited=function(channel,user){},this.onUserMuted=function(channel,user){},this.onUserUnmuted=function(channel,user){},this.onUserBanned=function(channel,user){},this.onUserUnbanned=function(channel,user){},this.onChannelFrozen=function(channel){},this.onChannelUnfrozen=function(channel){},this.onChannelChanged=function(channel){},this.onChannelDeleted=function(channel){}},this.addChannelHandler=function(id,handler){SendBird.getInstance().channelHandlers[id]=handler},this.removeChannelHandler=function(id){delete SendBird.getInstance().channelHandlers[id]},this.removeAllChannelHandlers=function(){SendBird.getInstance().channelHandlers={}},this.ConnectionHandler=function(){this.onReconnectStarted=function(){},this.onReconnectSucceeded=function(){},this.onReconnectFailed=function(){}},this.addConnectionHandler=function(id,cb){SendBird.getInstance().connectionHandlers[id]=cb},this.removeConnectionHandler=function(id){delete SendBird.getInstance().connectionHandlers[id]},this.removeAllConnectionHandlers=function(){SendBird.getInstance().connectionHandlers={}},this.createUserListQuery=function(userIds){return userIds?new UserListQuery(UserListQuery.FILTERED_USER,userIds):new UserListQuery(UserListQuery.ALL_USER)},this.createBlockedUserListQuery=function(){return new UserListQuery(UserListQuery.BLOCKED_USER)},this.getApplicationId=function(){return appId},this.getDebugMode=function(){return DEBUG},this.setDebugMode=function(isDebug){DEBUG=isDebug},this.setDebugHostMode=function(isDebug){DEBUG_HOST=isDebug},this.setAPIHost=function(host){API_HOST=host},this.setWSHost=function(host){WS_HOST=host},this.clearCurrentApiHost=function(){this.customApiHost=null},this.getCurrentApiHost=function(){return this.customApiHost?this.customApiHost:API_HOST},this.clearCurrentWsHost=function(){this.customWsHost=null},this.getCurrentWsHost=function(){return this.customWsHost?this.customWsHost:WS_HOST},this.setErrorFirstCallback=function(moveToFirst){errorFirstCallback=moveToFirst},this.getConnectionState=function(){if(!SendBird.getInstance())return this.connectionState.CLOSED;try{return SendBird.getInstance().wsClient?SendBird.getInstance().wsClient.getConnectionState():SendBird.getInstance().connectionState.CLOSED}catch(e){return SendBird.getInstance().connectionState.CLOSED}},this.hasLoggedIn=function(){return SendBird.getInstance().currentUser&&APIClient.getInstance().sessionKey};var getAckInfo=function(requestId){return ackStateMap.hasOwnProperty(requestId)?ackStateMap[requestId]:null},messageReceived=function(message){var cmd=new Command(message);if(cmd.requestId){var ackInfo=getAckInfo(cmd.requestId);if(null==ackInfo)return;clearTimeout(ackInfo.timer);var cb=ackInfo.handler;if(cb)if("EROR"==cmd.command){var error=cmd.getJsonElement(),errCode=error.code,errMessage=error.message;cb(cmd,new SendBirdException(errMessage,errCode))}else cb(cmd,null)}else switch(cmd.command){case"LOGI":if(SendBird.getInstance().loginTimer){clearTimeout(SendBird.getInstance().loginTimer),SendBird.getInstance().loginTimer=null,SendBird.getInstance().onLoginTimerCancel=null;var logiPayload=cmd.getJsonElement();if(logiPayload.hasOwnProperty("error")){var errCode=logiPayload.code,errMessage=logiPayload.message;SendBird.getInstance().loginHandler(null,new SendBirdException(errMessage,errCode))}else logiPayload.hasOwnProperty("key")&&(APIClient.getInstance().sessionKey=logiPayload.key),logiPayload.hasOwnProperty("ekey")&&(APIClient.getInstance().ekey=logiPayload.ekey),logiPayload.hasOwnProperty("user_id")&&(SendBird.getInstance().currentUser=new User(logiPayload)),SendBird.getInstance().loginHandler(SendBird.getInstance().currentUser,null)}break;case"MESG":case"FILE":case"BRDM":case"ADMM":var msg="",is_silent=!1;if("MESG"==cmd.command?msg=new UserMessage(cmd.getJsonElement()):"FILE"==cmd.command?msg=new FileMessage(cmd.getJsonElement()):(msg=new AdminMessage(cmd.getJsonElement()),cmd.getJsonElement().hasOwnProperty("silent")&&(is_silent=cmd.getJsonElement().silent)),!msg)return;if(msg.isGroupChannel()){var isAlreadyInCache=GroupChannel.cachedChannels.hasOwnProperty(msg.channelUrl);GroupChannel.getChannel(msg.channelUrl,function(channel,error){if(errorFirstCallback){var temp=channel;channel=error,error=temp}if(error)return void(cb&&cb(null,error));if(msg._sender&&channel.memberMap.hasOwnProperty(msg._sender.userId)){var oldMember=channel.memberMap[msg._sender.userId];oldMember.nickname!=msg._sender.nickname&&(oldMember.nickname=msg._sender.nickname),oldMember.profileUrl!=msg._sender.profileUrl&&(oldMember.profileUrl=msg._sender.profileUrl)}var me=SendBird.getInstance().currentUser;if(me&&msg._sender&&me.userId==msg._sender.userId&&(me.nickname!=msg._sender.nickname&&(me.nickname=msg._sender.nickname),me.profileUrl!=msg._sender.profileUrl&&(me.profileUrl=msg._sender.profileUrl)),!is_silent){ -isAlreadyInCache&&(channel.updatedLocal?(channel.lastMessage=msg,msg.sender&&msg.sender.userId==SendBird.getInstance().getCurrentUserId()||channel.unreadMessageCount++):(!channel.lastMessage||channel.lastMessage.createdAt0){channel.unreadMessageCount=0;for(var i in SendBird.getInstance().channelHandlers){var handler=SendBird.getInstance().channelHandlers[i];handler.onChannelChanged(channel)}}}else if(0==channel.unreadMessageCount)for(var i in SendBird.getInstance().channelHandlers){var handler=SendBird.getInstance().channelHandlers[i];handler.onChannelChanged(channel)}}else{channel.updateReadReceipt(rst.reader.userId,rst.timestamp);for(var i in SendBird.getInstance().channelHandlers){var handler=SendBird.getInstance().channelHandlers[i];handler.onReadReceiptUpdated(channel)}}});break;case"TPST":case"TPEN":case"MTIO":break;case"SYEV":processChannelEvent(cmd);break;case"DELM":var obj=cmd.getJsonElement(),channelType=String(obj.channel_type),channelUrl=String(obj.channel_url),msgId=String(obj.msg_id);switch(channelType){case BaseChannel.CHANNEL_TYPE_OPEN:OpenChannel.getChannel(channelUrl,function(channel,error){if(errorFirstCallback){var temp=channel;channel=error,error=temp}if(error)return void console.log("Discard a command.");for(var i in SendBird.getInstance().channelHandlers){SendBird.getInstance().channelHandlers[i].onMessageDeleted(channel,msgId)}});break;case BaseChannel.CHANNEL_TYPE_GROUP:GroupChannel.getChannel(channelUrl,function(channel,error){if(errorFirstCallback){var temp=channel;channel=error,error=temp}if(error)return void console.log("Discard a command.");for(var i in SendBird.getInstance().channelHandlers){SendBird.getInstance().channelHandlers[i].onMessageDeleted(channel,msgId)}})}}},processChannelEvent=function(cmd){var event=new ChannelEvent(cmd.getJsonElement());switch(event.category){case ChannelEvent.CATEGORY_CHANNEL_JOIN:case ChannelEvent.CATEGORY_CHANNEL_LEAVE:GroupChannel.getChannel(event.channelUrl,function(channel,error){if(errorFirstCallback){var temp=channel;channel=error,error=temp}if(error)return void console.log("Discard a command: "+cmd.command+":"+event.category);var user=new User(event.data);if(event.category==ChannelEvent.CATEGORY_CHANNEL_JOIN){channel.addMember(user);for(var i in SendBird.getInstance().channelHandlers){var handler=SendBird.getInstance().channelHandlers[i];handler.onUserJoined(channel,user)}}else{channel.removeMember(user);for(var i in SendBird.getInstance().channelHandlers){var handler=SendBird.getInstance().channelHandlers[i];handler.onUserLeft(channel,user)}}});break;case ChannelEvent.CATEGORY_TYPING_START:case ChannelEvent.CATEGORY_TYPING_END:GroupChannel.getChannel(event.channelUrl,function(channel,error){if(errorFirstCallback){var temp=channel;channel=error,error=temp}if(error)return void console.log("Discard a command: "+cmd.command+":"+event.category);var user=new User(event.data);event.category==ChannelEvent.CATEGORY_TYPING_START?channel.updateTypingStatus(user,!0):channel.updateTypingStatus(user,!1);for(var i in SendBird.getInstance().channelHandlers){SendBird.getInstance().channelHandlers[i].onTypingStatusUpdated(channel)}});break;case ChannelEvent.CATEGORY_CHANNEL_ENTER:case ChannelEvent.CATEGORY_CHANNEL_EXIT:OpenChannel.getChannel(event.channelUrl,function(channel,error){if(errorFirstCallback){var temp=channel;channel=error,error=temp}if(error)return void console.log("Discard a command: "+cmd.command+":"+event.category);event.data.hasOwnProperty("participant_count")&&(channel.participantCount=event.data.participant_count);var user=new User(event.data);if(event.category==ChannelEvent.CATEGORY_CHANNEL_ENTER)for(var i in SendBird.getInstance().channelHandlers){var handler=SendBird.getInstance().channelHandlers[i];handler.onUserEntered(channel,user)}else for(var i in SendBird.getInstance().channelHandlers){var handler=SendBird.getInstance().channelHandlers[i];handler.onUserExited(channel,user)}});break;case ChannelEvent.CATEGORY_USER_CHANNEL_MUTE:case ChannelEvent.CATEGORY_USER_CHANNEL_UNMUTE:OpenChannel.getChannel(event.channelUrl,function(channel,error){if(errorFirstCallback){var temp=channel;channel=error,error=temp}if(error)return void console.log("Discard a command: "+cmd.command+":"+event.category);var user=new User(event.data);if(event.category==ChannelEvent.CATEGORY_USER_CHANNEL_MUTE)for(var i in SendBird.getInstance().channelHandlers){var handler=SendBird.getInstance().channelHandlers[i];handler.onUserMuted(channel,user)}else for(var i in SendBird.getInstance().channelHandlers){var handler=SendBird.getInstance().channelHandlers[i];handler.onUserUnmuted(channel,user)}});break;case ChannelEvent.CATEGORY_USER_CHANNEL_BAN:case ChannelEvent.CATEGORY_USER_CHANNEL_UNBAN:OpenChannel.getChannel(event.channelUrl,function(channel,error){if(errorFirstCallback){var temp=channel;channel=error,error=temp}if(error)return void console.log("Discard a command: "+cmd.command+":"+event.category);var user=new User(event.data);if(event.category==ChannelEvent.CATEGORY_USER_CHANNEL_BAN)for(var i in SendBird.getInstance().channelHandlers){var handler=SendBird.getInstance().channelHandlers[i];handler.onUserBanned(channel,user)}else for(var i in SendBird.getInstance().channelHandlers){var handler=SendBird.getInstance().channelHandlers[i];handler.onUserUnbanned(channel,user)}});break;case ChannelEvent.CATEGORY_CHANNEL_FREEZE:case ChannelEvent.CATEGORY_CHANNEL_UNFREEZE:OpenChannel.getChannel(event.channelUrl,function(channel,error){if(errorFirstCallback){var temp=channel;channel=error,error=temp}if(error)return void console.log("Discard a command: "+cmd.command+":"+event.category);if(event.category==ChannelEvent.CATEGORY_CHANNEL_FREEZE)for(var i in SendBird.getInstance().channelHandlers){var handler=SendBird.getInstance().channelHandlers[i];handler.onChannelFrozen(channel)}else for(var i in SendBird.getInstance().channelHandlers){var handler=SendBird.getInstance().channelHandlers[i];handler.onChannelUnfrozen(channel)}});break;case ChannelEvent.CATEGORY_CHANNEL_DELETED:if(event.isGroupChannel()){GroupChannel.removeCachedChannel(event.channelUrl);for(var i in SendBird.getInstance().channelHandlers){var handler=SendBird.getInstance().channelHandlers[i];handler.onChannelDeleted(event.channelUrl,"group")}}else{OpenChannel.removeCachedChannel(event.channelUrl);for(var i in SendBird.getInstance().channelHandlers){var handler=SendBird.getInstance().channelHandlers[i];handler.onChannelDeleted(event.channelUrl,"open")}}break;case ChannelEvent.CATEGORY_CHANNEL_PROP_CHANGED:event.isOpenChannel()?OpenChannel.getChannelWithoutCache(event.channelUrl,function(channel,error){if(errorFirstCallback){var temp=channel;channel=error,error=temp}if(error)return void console.log("Discard a command: "+cmd.command+":"+event.category);for(var i in SendBird.getInstance().channelHandlers){SendBird.getInstance().channelHandlers[i].onChannelChanged(channel)}}):GroupChannel.getChannelWithoutCache(event.channelUrl,function(channel,error){if(errorFirstCallback){var temp=channel;channel=error,error=temp}if(error)return void console.log("Discard a command: "+cmd.command+":"+event.category);for(var i in SendBird.getInstance().channelHandlers){SendBird.getInstance().channelHandlers[i].onChannelChanged(channel)}})}};this.setPushTemplate=function(templateName,cb){return!templateName||templateName!==this.PUSH_TEMPLATE_DEFAULT&&templateName!==this.PUSH_TEMPLATE_ALTERNATIVE?void callbackWrapper(null,new SendBirdException("Invalid arguments.",SendBirdError.INVALID_PARAMETER),cb):this.currentUser?void APIClient.getInstance().setPushTemplate(this.getCurrentUserId(),templateName,function(res,err){if(err)return void callbackWrapper(null,err,cb);var templateName=res.name.toString();callbackWrapper(templateName,null,cb)}):void callbackWrapper(null,new SendBirdException("Connection must be made before you set push template",SendBirdError.CONNECTION_REQUIRED),cb)},this.getPushTemplate=function(cb){if(!this.currentUser)return void callbackWrapper(null,new SendBirdException("Connection must be made before you get push template",SendBirdError.CONNECTION_REQUIRED),cb);APIClient.getInstance().getPushTemplate(this.getCurrentUserId(),function(res,err){if(err)return void callbackWrapper(null,err,cb);var templateName=res.name.toString();callbackWrapper(templateName,null,cb)})},this.connect=function(){var args=Array.prototype.slice.call(arguments),userId=null,accessToken=null,cb=null;switch("function"==typeof args.slice(-1)[0]&&(cb=args.pop()),args.length){case 1:userId=args[0];break;case 2:userId=args[0],accessToken=args[1];break;case 3:userId=args[0],this.customApiHost=args[1],this.customWsHost=args[2];break;case 4:userId=args[0],accessToken=args[1],this.customApiHost=args[2],this.customWsHost=args[3];break;default:DEBUG&&console.log("sb.connect args length error: ",arguments)}userId&&0!=userId.length?(disconnectWithLogout(!0,null),connectWS(userId,accessToken,cb)):callbackWrapper(null,new SendBirdException("Invalid arguments.",SendBirdError.INVALID_PARAMETER),cb)};var isBackgroundMode=!1,notClosed=!1,enableStateChange=!0;this.setBackgroundState=function(){!isBackgroundMode&&enableStateChange&&(isBackgroundMode=!0,this.getConnectionState()!=this.connectionState.CLOSED?(notClosed=!0,disconnectWithLogout(!1,null)):notClosed=!1)},this.setForegroundState=function(){isBackgroundMode&&enableStateChange&&(isBackgroundMode=!1,notClosed&&this.currentUser&&(reconnectCount=0,reconnectWS(this.getCurrentUserId(),!0)))},this.disableStateChange=function(){enableStateChange=!1},this.enableStateChange=function(){enableStateChange=!0},this.disconnect=function(cb){disconnectWithLogout(!0,cb)},this.reconnect=function(){if(!APIClient.getInstance().sessionKey||!this.currentUser)return!1;var shouldCallStarted=!0;return reconnectCount>0&&(shouldCallStarted=!1),disconnectWithLogout(!1,null),reconnectCount=0,reconnectWS(this.getCurrentUserId(),shouldCallStarted),!0};var disconnectWithLogout=function(isLogout,cb){var _self=this;SendBird.getInstance().loginTimer&&(clearTimeout(SendBird.getInstance().loginTimer),SendBird.getInstance().onLoginTimerCancel&&(SendBird.getInstance().onLoginTimerCancel(),SendBird.getInstance().onLoginTimerCancel=null),SendBird.getInstance().loginTimer=null),SendBird.getInstance().reconnectTimer&&(clearTimeout(SendBird.getInstance().reconnectTimer),SendBird.getInstance().onReconnectTimerCancel&&(SendBird.getInstance().onReconnectTimerCancel(),SendBird.getInstance().onReconnectTimerCancel=null),SendBird.getInstance().reconnectTimer=null),SendBird.getInstance().wsClient&&(reconnectCount=0,SendBird.getInstance().wsClient.disconnect(!0),SendBird.getInstance().wsClient=null),function(){if(isLogout){OpenChannel.clearEnteredChannels(),OpenChannel.clearCache(),GroupChannel.clearCache(),SendBird.getInstance().globalTimer&&(clearTimeout(_self.globalTimer),SendBird.getInstance().globalTimer=null);for(var reqId in SendBird.getInstance().ackStateMap)clearTimeout(SendBird.getInstance().ackStateMap[reqId].timer);SendBird.getInstance().ackStateMap={},SendBird.getInstance().currentUser=null,APIClient.getInstance().sessionKey=null,APIClient.getInstance().ekey=null}callbackWrapper(null,null,cb)}()},reconnectWS=function(userId,shouldCallStarted){if(SendBird.getInstance().reconnectTimer)DEBUG&&console.log("still reconnecting");else{if((reconnectCount+=1)<=1){if(shouldCallStarted)for(var i in SendBird.getInstance().connectionHandlers){var handler=SendBird.getInstance().connectionHandlers[i];handler.onReconnectStarted(i)}reconnectDelay=0}else reconnectDelay=3e3*Math.pow(2,reconnectCount-2);if(!userId||!APIClient.getInstance().sessionKey||reconnectCount>=6){disconnectWithLogout(!1,null),reconnectCount=0;for(var i in SendBird.getInstance().connectionHandlers){var handler=SendBird.getInstance().connectionHandlers[i];handler.onReconnectFailed(i)}return}SendBird.getInstance().onReconnectTimerCancel=function(){reconnectCount=0},SendBird.getInstance().reconnectTimer=setTimeout(function(){SendBird.getInstance().reconnectTimer=null,SendBird.getInstance().onReconnectTimerCancel=null,SendBird.getInstance().wsClient&&SendBird.getInstance().wsClient.disconnect(!0);var WSClientHandler=new WSClient.WSClientHandler;SendBird.getInstance().wsClient=new WSClient(WSClientHandler),SendBird.getInstance().loginHandler=function(user){reconnectCount=0;for(var i in OpenChannel.enteredChannels){OpenChannel.enteredChannels[i].enter()}for(var i in SendBird.getInstance().connectionHandlers){SendBird.getInstance().connectionHandlers[i].onReconnectSucceeded(i)}},WSClientHandler.onOpen=function(){DEBUG&&console.log("reconnectWS onOpen"),SendBird.getInstance().loginTimer=setTimeout(function(){DEBUG&&console.log("reconnectWS loginTimer timedout"),SendBird.getInstance().loginTimer=null,reconnectWS(userId,!0)},1e4),SendBird.getInstance().onLoginTimerCancel=null},WSClientHandler.onMessage=function(message){messageReceived(message)},WSClientHandler.onError=function(){DEBUG&&console.log("reconnectWS onError"),reconnectWS(userId,!0)},WSClientHandler.onClose=function(){DEBUG&&console.log("reconnectWS onClose")};var API_HOST_OLD=SendBird.getInstance().getCurrentApiHost();APIClient.getInstance().checkRouting(function(result,error){if(error)return void reconnectWS(userId,!0);API_HOST_OLD!=result.API_HOST&&_ajaxCall(result.API_HOST,{},"GET",{},function(){}),SendBird.getInstance().wsClient.connect(userId,null,result.WS_HOST)})},reconnectDelay)}},connectWS=function(userId,accessToken,cb){var WSClientHandler=new WSClient.WSClientHandler;SendBird.getInstance().wsClient=new WSClient(WSClientHandler),WSClientHandler.onMessage=function(message){messageReceived(message)},SendBird.getInstance().loginHandler=function(user,sendbirdException){if(sendbirdException)SendBird.getInstance().disconnect(null),callbackWrapper(null,sendbirdException,cb);else{clearTimeout(SendBird.getInstance().globalTimer);var globalTimerLoop=function(){if(GroupChannel.cachedChannels)for(var i in GroupChannel.cachedChannels){var channel=GroupChannel.cachedChannels[i];if(channel.invalidateTypingStatus())for(var i2 in SendBird.getInstance().channelHandlers){var channelHandler=SendBird.getInstance().channelHandlers[i2];channelHandler.onTypingStatusUpdated(channel)}}SendBird.getInstance().globalTimer=setTimeout(function(){globalTimerLoop()},1e3)};globalTimerLoop(),callbackWrapper(user,null,cb)}},WSClientHandler.onOpen=function(e){SendBird.getInstance().loginTimer=setTimeout(function(){SendBird.getInstance().loginTimer=null,SendBird.getInstance().onLoginTimerCancel=null,SendBird.getInstance().disconnect(null),callbackWrapper(null,new SendBirdException("Connection timeout.",SendBirdError.LOGIN_TIMEOUT),cb)},1e4),SendBird.getInstance().onLoginTimerCancel=function(){callbackWrapper(null,new SendBirdException("Connection Cancelled.",SendBirdError.REQUEST_FAILED),cb)}},WSClientHandler.onError=function(error){DEBUG&&console.log("WSClientHandler.onError",error),APIClient.getInstance().sessionKey?reconnectWS(userId,!0):callbackWrapper(null,new SendBirdException("Websocket connection failed.",SendBirdError.WEBSOCKET_CONNECTION_FAILED),cb)},WSClientHandler.onClose=function(message){DEBUG&&console.log("WSClientHandler.onClose")},APIClient.getInstance().checkRouting(function(result,error){if(error)return void callbackWrapper(null,new SendBirdException("Connection routing failed.",SendBirdError.REQUEST_FAILED),cb);_ajaxCall(result.API_HOST,{},"GET",{},function(){}),SendBird.getInstance().wsClient.connect(userId,accessToken,result.WS_HOST)})};this.sendCommand=function(cmd,cb){if(!SendBird.getInstance().hasLoggedIn())return void(cb&&cb(null,new SendBirdException("Connection should be made first.",SendBirdError.CONNECTION_REQUIRED)));if(null==SendBird.getInstance().wsClient||SendBird.getInstance().wsClient.getConnectionState()!=SendBird.getInstance().connectionState.OPEN)return void(cb&&cb(null,new SendBirdException("Connection is not valid. Please reconnect.",SendBirdError.WEBSOCKET_CONNECTION_CLOSED)));if(cmd.isAckRequired()){var reqId=cmd.requestId,obj={handler:cb,timer:setTimeout(function(){cb(null,new SendBirdException("Command received no ack.",SendBirdError.ACK_TIMEOUT)),delete ackStateMap[reqId]},1e4)};ackStateMap[reqId]=obj,SendBird.getInstance().wsClient.send(cmd,function(response,error){if(error)return clearTimeout(obj.timer),void cb(null,error)})}else SendBird.getInstance().wsClient.send(cmd,cb)},this.updateCurrentUserInfoWithProfileImage=function(nickname,profileImage,cb){var _SELF=this;profileImage?APIClient.getInstance().uploadProfileImage(profileImage,function(response,error){if(error)return void callbackWrapper(null,error,cb);var result="object"==typeof response?response:JSON.parse(response),fileUrl=result.url;_SELF.updateCurrentUserInfo(nickname,fileUrl,cb)}):_SELF.updateCurrentUserInfo(nickname,null,cb)},this.updateCurrentUserInfo=function(nickname,profileUrl,cb){var _SELF=this;APIClient.getInstance().updateUserInfo(_SELF.getCurrentUserId(),nickname,profileUrl,function(response,error){if(error)return void callbackWrapper(null,error,cb);_SELF.currentUser&&(nickname&&(_SELF.currentUser.nickname=nickname),profileUrl&&(_SELF.currentUser.profileUrl=profileUrl)),callbackWrapper(_SELF.currentUser,null,cb)})},this.getPendingGCMToken=function(){return this.GCMPushToken},this.getPendingAPNSToken=function(){return this.APNSPushToken},this.registerGCMPushTokenForCurrentUser=function(gcmRegToken,cb){var _SELF=this;return gcmRegToken?this.currentUser?void APIClient.getInstance().registerGCMPushToken(this.getCurrentUserId(),gcmRegToken,function(response,error){if(error)return void callbackWrapper(_SELF.pushTokenRegistrationState.ERROR,error,cb);_SELF.GCMPushToken="",callbackWrapper(_SELF.pushTokenRegistrationState.SUCCESS,null,cb)}):(_SELF.GCMPushToken=gcmRegToken,void callbackWrapper(_SELF.pushTokenRegistrationState.PENDING,null,cb)):void callbackWrapper(_SELF.pushTokenRegistrationState.ERROR,new SendBirdException("Invalid token",SendBirdError.INVALID_PARAMETER),cb)},this.unregisterGCMPushTokenForCurrentUser=function(gcmRegToken,cb){if(!gcmRegToken)return void callbackWrapper(null,new SendBirdException("Invalid token",SendBirdError.INVALID_PARAMETER),cb);APIClient.getInstance().unregisterGCMPushToken(this.getCurrentUserId(),gcmRegToken,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(null,null,cb)})},this.unregisterGCMPushTokenAllForCurrentUser=function(cb){APIClient.getInstance().unregisterGCMPushTokenAll(this.getCurrentUserId(),function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(null,null,cb)})},this.registerAPNSPushTokenForCurrentUser=function(apnsRegToken,cb){var _SELF=this;return apnsRegToken?this.currentUser?void APIClient.getInstance().registerAPNSPushToken(this.getCurrentUserId(),apnsRegToken,function(response,error){if(error)return void callbackWrapper(_SELF.pushTokenRegistrationState.ERROR,error,cb);_SELF.APNSPushToken="",callbackWrapper(_SELF.pushTokenRegistrationState.SUCCESS,null,cb)}):(_SELF.APNSPushToken=apnsRegToken,void callbackWrapper(_SELF.pushTokenRegistrationState.PENDING,null,cb)):void callbackWrapper(_SELF.pushTokenRegistrationState.ERROR,new SendBirdException("Invalid token",SendBirdError.INVALID_PARAMETER),cb)},this.unregisterAPNSPushTokenForCurrentUser=function(apnsRegToken,cb){APIClient.getInstance().unregisterAPNSPushToken(this.getCurrentUserId(),apnsRegToken,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(null,null,cb)})},this.unregisterAPNSPushTokenAllForCurrentUser=function(cb){APIClient.getInstance().unregisterAPNSPushTokenAll(this.getCurrentUserId(),function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(null,null,cb)})},this.unregisterPushTokenAllForCurrentUser=function(cb){APIClient.getInstance().unregisterAPNSPushTokenAll(this.getCurrentUserId(),function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(null,null,cb)})},this.setDoNotDisturb=function(doNotDisturbOn,startHour,startMin,endHour,endMin,timezone,cb){var _SELF=this;if(startHour<0||startHour>23||startMin<0||startMin>59||endHour<0||endHour>23||endMin<0||endMin>59)return void callbackWrapper(null,new SendBirdException("Invalid arguments.",SendBirdError.INVALID_PARAMETER),cb);APIClient.getInstance().setDoNotDisturb(_SELF.getCurrentUserId(),doNotDisturbOn,startHour,startMin,endHour,endMin,timezone,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(null,null,cb)})},this.getDoNotDisturb=function(cb){var _SELF=this;APIClient.getInstance().getDoNotDisturb(_SELF.getCurrentUserId(),function(response,error){if(error)return void callbackWrapper(null,error,cb);var data={doNotDisturbOn:response.do_not_disturb,startHour:response.start_hour,startMin:response.start_min,endHour:response.end_hour,endMin:response.end_min,timezone:response.timezone};callbackWrapper(data,null,cb)})},this.blockUser=function(userToBlock,cb){if("object"!=typeof userToBlock)return void callbackWrapper(null,new SendBirdException("You have to pass user object.",SendBirdError.INVALID_PARAMETER),cb);this.blockUserWithUserId(userToBlock.userId,cb)},this.blockUserWithUserId=function(userIdToBlock,cb){if(this.getCurrentUserId()==userIdToBlock)return void callbackWrapper(null,new SendBirdException("You can not block yourself.",SendBirdError.INVALID_PARAMETER),cb);APIClient.getInstance().blockUser(this.getCurrentUserId(),userIdToBlock,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(new User(response),null,cb)})},this.unblockUser=function(blockedUser,cb){if("object"!=typeof blockedUser)return void callbackWrapper(null,new SendBirdException("You have to pass user object.",SendBirdError.INVALID_PARAMETER),cb);this.unblockUserWithUserId(blockedUser.userId,cb)},this.unblockUserWithUserId=function(blockedUserId,cb){if(this.getCurrentUserId()==blockedUserId)return void callbackWrapper(null,new SendBirdException("You can not unblock yourself.",SendBirdError.INVALID_PARAMETER),cb);APIClient.getInstance().unblockUser(this.getCurrentUserId(),blockedUserId,function(response,error){if(error)return void callbackWrapper(null,error,cb);callbackWrapper(null,null,cb)})}},sendbirdInstance=null;return SendBird.getInstance=function(){return null===sendbirdInstance?null:sendbirdInstance},{SendBird:SendBird}},singletonObject=null;return function(){var SendBird=function(param){if(param.newInstance||!singletonObject){var obj=new SendBirdObject;singletonObject=new obj.SendBird(param)}return singletonObject};return SendBird.getInstance=function(){return null===singletonObject?null:singletonObject},SendBird.version="3.0.31",{SendBird:SendBird}}().SendBird}); \ No newline at end of file diff --git a/web-widget/build/widget.SendBird.js b/web-widget/build/widget.SendBird.js deleted file mode 100644 index eb9b2ebc..00000000 --- a/web-widget/build/widget.SendBird.js +++ /dev/null @@ -1,13898 +0,0 @@ -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 316); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -var global = __webpack_require__(2) - , core = __webpack_require__(24) - , hide = __webpack_require__(12) - , redefine = __webpack_require__(13) - , ctx = __webpack_require__(25) - , PROTOTYPE = 'prototype'; - -var $export = function(type, name, source){ - var IS_FORCED = type & $export.F - , IS_GLOBAL = type & $export.G - , IS_STATIC = type & $export.S - , IS_PROTO = type & $export.P - , IS_BIND = type & $export.B - , target = IS_GLOBAL ? global : IS_STATIC ? global[name] || (global[name] = {}) : (global[name] || {})[PROTOTYPE] - , exports = IS_GLOBAL ? core : core[name] || (core[name] = {}) - , expProto = exports[PROTOTYPE] || (exports[PROTOTYPE] = {}) - , key, own, out, exp; - if(IS_GLOBAL)source = name; - for(key in source){ - // contains in native - own = !IS_FORCED && target && target[key] !== undefined; - // export native or passed - out = (own ? target : source)[key]; - // bind timers to global for call from export context - exp = IS_BIND && own ? ctx(out, global) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out; - // extend global - if(target)redefine(target, key, out, type & $export.U); - // export - if(exports[key] != out)hide(exports, key, exp); - if(IS_PROTO && expProto[key] != out)expProto[key] = out; - } -}; -global.core = core; -// type bitmap -$export.F = 1; // forced -$export.G = 2; // global -$export.S = 4; // static -$export.P = 8; // proto -$export.B = 16; // bind -$export.W = 32; // wrap -$export.U = 64; // safe -$export.R = 128; // real proto method for `library` -module.exports = $export; - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var isObject = __webpack_require__(4); -module.exports = function(it){ - if(!isObject(it))throw TypeError(it + ' is not an object!'); - return it; -}; - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 -var global = module.exports = typeof window != 'undefined' && window.Math == Math - ? window : typeof self != 'undefined' && self.Math == Math ? self : Function('return this')(); -if(typeof __g == 'number')__g = global; // eslint-disable-line no-undef - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -module.exports = function(exec){ - try { - return !!exec(); - } catch(e){ - return true; - } -}; - -/***/ }), -/* 4 */ -/***/ (function(module, exports) { - -module.exports = function(it){ - return typeof it === 'object' ? it !== null : typeof it === 'function'; -}; - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -var store = __webpack_require__(60)('wks') - , uid = __webpack_require__(40) - , Symbol = __webpack_require__(2).Symbol - , USE_SYMBOL = typeof Symbol == 'function'; - -var $exports = module.exports = function(name){ - return store[name] || (store[name] = - USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : uid)('Symbol.' + name)); -}; - -$exports.store = store; - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -// Thank's IE8 for his funny defineProperty -module.exports = !__webpack_require__(3)(function(){ - return Object.defineProperty({}, 'a', {get: function(){ return 7; }}).a != 7; -}); - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -var anObject = __webpack_require__(1) - , IE8_DOM_DEFINE = __webpack_require__(97) - , toPrimitive = __webpack_require__(23) - , dP = Object.defineProperty; - -exports.f = __webpack_require__(6) ? Object.defineProperty : function defineProperty(O, P, Attributes){ - anObject(O); - P = toPrimitive(P, true); - anObject(Attributes); - if(IE8_DOM_DEFINE)try { - return dP(O, P, Attributes); - } catch(e){ /* empty */ } - if('get' in Attributes || 'set' in Attributes)throw TypeError('Accessors not supported!'); - if('value' in Attributes)O[P] = Attributes.value; - return O; -}; - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -// 7.1.15 ToLength -var toInteger = __webpack_require__(31) - , min = Math.min; -module.exports = function(it){ - return it > 0 ? min(toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991 -}; - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -// 7.1.13 ToObject(argument) -var defined = __webpack_require__(19); -module.exports = function(it){ - return Object(defined(it)); -}; - -/***/ }), -/* 10 */ -/***/ (function(module, exports) { - -var hasOwnProperty = {}.hasOwnProperty; -module.exports = function(it, key){ - return hasOwnProperty.call(it, key); -}; - -/***/ }), -/* 11 */ -/***/ (function(module, exports) { - -module.exports = function(it){ - if(typeof it != 'function')throw TypeError(it + ' is not a function!'); - return it; -}; - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -var dP = __webpack_require__(7) - , createDesc = __webpack_require__(30); -module.exports = __webpack_require__(6) ? function(object, key, value){ - return dP.f(object, key, createDesc(1, value)); -} : function(object, key, value){ - object[key] = value; - return object; -}; - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -var global = __webpack_require__(2) - , hide = __webpack_require__(12) - , has = __webpack_require__(10) - , SRC = __webpack_require__(40)('src') - , TO_STRING = 'toString' - , $toString = Function[TO_STRING] - , TPL = ('' + $toString).split(TO_STRING); - -__webpack_require__(24).inspectSource = function(it){ - return $toString.call(it); -}; - -(module.exports = function(O, key, val, safe){ - var isFunction = typeof val == 'function'; - if(isFunction)has(val, 'name') || hide(val, 'name', key); - if(O[key] === val)return; - if(isFunction)has(val, SRC) || hide(val, SRC, O[key] ? '' + O[key] : TPL.join(String(key))); - if(O === global){ - O[key] = val; - } else { - if(!safe){ - delete O[key]; - hide(O, key, val); - } else { - if(O[key])O[key] = val; - else hide(O, key, val); - } - } -// add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative -})(Function.prototype, TO_STRING, function toString(){ - return typeof this == 'function' && this[SRC] || $toString.call(this); -}); - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -var $export = __webpack_require__(0) - , fails = __webpack_require__(3) - , defined = __webpack_require__(19) - , quot = /"/g; -// B.2.3.2.1 CreateHTML(string, tag, attribute, value) -var createHTML = function(string, tag, attribute, value) { - var S = String(defined(string)) - , p1 = '<' + tag; - if(attribute !== '')p1 += ' ' + attribute + '="' + String(value).replace(quot, '"') + '"'; - return p1 + '>' + S + ''; -}; -module.exports = function(NAME, exec){ - var O = {}; - O[NAME] = exec(createHTML); - $export($export.P + $export.F * fails(function(){ - var test = ''[NAME]('"'); - return test !== test.toLowerCase() || test.split('"').length > 3; - }), 'String', O); -}; - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -// to indexed object, toObject with fallback for non-array-like ES3 strings -var IObject = __webpack_require__(49) - , defined = __webpack_require__(19); -module.exports = function(it){ - return IObject(defined(it)); -}; - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -var pIE = __webpack_require__(50) - , createDesc = __webpack_require__(30) - , toIObject = __webpack_require__(15) - , toPrimitive = __webpack_require__(23) - , has = __webpack_require__(10) - , IE8_DOM_DEFINE = __webpack_require__(97) - , gOPD = Object.getOwnPropertyDescriptor; - -exports.f = __webpack_require__(6) ? gOPD : function getOwnPropertyDescriptor(O, P){ - O = toIObject(O); - P = toPrimitive(P, true); - if(IE8_DOM_DEFINE)try { - return gOPD(O, P); - } catch(e){ /* empty */ } - if(has(O, P))return createDesc(!pIE.f.call(O, P), O[P]); -}; - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.1.2.9 / 15.2.3.2 Object.getPrototypeOf(O) -var has = __webpack_require__(10) - , toObject = __webpack_require__(9) - , IE_PROTO = __webpack_require__(77)('IE_PROTO') - , ObjectProto = Object.prototype; - -module.exports = Object.getPrototypeOf || function(O){ - O = toObject(O); - if(has(O, IE_PROTO))return O[IE_PROTO]; - if(typeof O.constructor == 'function' && O instanceof O.constructor){ - return O.constructor.prototype; - } return O instanceof Object ? ObjectProto : null; -}; - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - -var toString = {}.toString; - -module.exports = function(it){ - return toString.call(it).slice(8, -1); -}; - -/***/ }), -/* 19 */ -/***/ (function(module, exports) { - -// 7.2.1 RequireObjectCoercible(argument) -module.exports = function(it){ - if(it == undefined)throw TypeError("Can't call method on " + it); - return it; -}; - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -var fails = __webpack_require__(3); - -module.exports = function(method, arg){ - return !!method && fails(function(){ - arg ? method.call(null, function(){}, 1) : method.call(null); - }); -}; - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -// 0 -> Array#forEach -// 1 -> Array#map -// 2 -> Array#filter -// 3 -> Array#some -// 4 -> Array#every -// 5 -> Array#find -// 6 -> Array#findIndex -var ctx = __webpack_require__(25) - , IObject = __webpack_require__(49) - , toObject = __webpack_require__(9) - , toLength = __webpack_require__(8) - , asc = __webpack_require__(129); -module.exports = function(TYPE, $create){ - var IS_MAP = TYPE == 1 - , IS_FILTER = TYPE == 2 - , IS_SOME = TYPE == 3 - , IS_EVERY = TYPE == 4 - , IS_FIND_INDEX = TYPE == 6 - , NO_HOLES = TYPE == 5 || IS_FIND_INDEX - , create = $create || asc; - return function($this, callbackfn, that){ - var O = toObject($this) - , self = IObject(O) - , f = ctx(callbackfn, that, 3) - , length = toLength(self.length) - , index = 0 - , result = IS_MAP ? create($this, length) : IS_FILTER ? create($this, 0) : undefined - , val, res; - for(;length > index; index++)if(NO_HOLES || index in self){ - val = self[index]; - res = f(val, index, O); - if(TYPE){ - if(IS_MAP)result[index] = res; // map - else if(res)switch(TYPE){ - case 3: return true; // some - case 5: return val; // find - case 6: return index; // findIndex - case 2: result.push(val); // filter - } else if(IS_EVERY)return false; // every - } - } - return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : result; - }; -}; - -/***/ }), -/* 22 */ -/***/ (function(module, exports, __webpack_require__) { - -// most Object methods by ES6 should accept primitives -var $export = __webpack_require__(0) - , core = __webpack_require__(24) - , fails = __webpack_require__(3); -module.exports = function(KEY, exec){ - var fn = (core.Object || {})[KEY] || Object[KEY] - , exp = {}; - exp[KEY] = exec(fn); - $export($export.S + $export.F * fails(function(){ fn(1); }), 'Object', exp); -}; - -/***/ }), -/* 23 */ -/***/ (function(module, exports, __webpack_require__) { - -// 7.1.1 ToPrimitive(input [, PreferredType]) -var isObject = __webpack_require__(4); -// instead of the ES6 spec version, we didn't implement @@toPrimitive case -// and the second argument - flag - preferred type is a string -module.exports = function(it, S){ - if(!isObject(it))return it; - var fn, val; - if(S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it)))return val; - if(typeof (fn = it.valueOf) == 'function' && !isObject(val = fn.call(it)))return val; - if(!S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it)))return val; - throw TypeError("Can't convert object to primitive value"); -}; - -/***/ }), -/* 24 */ -/***/ (function(module, exports) { - -var core = module.exports = {version: '2.4.0'}; -if(typeof __e == 'number')__e = core; // eslint-disable-line no-undef - -/***/ }), -/* 25 */ -/***/ (function(module, exports, __webpack_require__) { - -// optional / simple context binding -var aFunction = __webpack_require__(11); -module.exports = function(fn, that, length){ - aFunction(fn); - if(that === undefined)return fn; - switch(length){ - case 1: return function(a){ - return fn.call(that, a); - }; - case 2: return function(a, b){ - return fn.call(that, a, b); - }; - case 3: return function(a, b, c){ - return fn.call(that, a, b, c); - }; - } - return function(/* ...args */){ - return fn.apply(that, arguments); - }; -}; - -/***/ }), -/* 26 */ -/***/ (function(module, exports, __webpack_require__) { - -var Map = __webpack_require__(113) - , $export = __webpack_require__(0) - , shared = __webpack_require__(60)('metadata') - , store = shared.store || (shared.store = new (__webpack_require__(116))); - -var getOrCreateMetadataMap = function(target, targetKey, create){ - var targetMetadata = store.get(target); - if(!targetMetadata){ - if(!create)return undefined; - store.set(target, targetMetadata = new Map); - } - var keyMetadata = targetMetadata.get(targetKey); - if(!keyMetadata){ - if(!create)return undefined; - targetMetadata.set(targetKey, keyMetadata = new Map); - } return keyMetadata; -}; -var ordinaryHasOwnMetadata = function(MetadataKey, O, P){ - var metadataMap = getOrCreateMetadataMap(O, P, false); - return metadataMap === undefined ? false : metadataMap.has(MetadataKey); -}; -var ordinaryGetOwnMetadata = function(MetadataKey, O, P){ - var metadataMap = getOrCreateMetadataMap(O, P, false); - return metadataMap === undefined ? undefined : metadataMap.get(MetadataKey); -}; -var ordinaryDefineOwnMetadata = function(MetadataKey, MetadataValue, O, P){ - getOrCreateMetadataMap(O, P, true).set(MetadataKey, MetadataValue); -}; -var ordinaryOwnMetadataKeys = function(target, targetKey){ - var metadataMap = getOrCreateMetadataMap(target, targetKey, false) - , keys = []; - if(metadataMap)metadataMap.forEach(function(_, key){ keys.push(key); }); - return keys; -}; -var toMetaKey = function(it){ - return it === undefined || typeof it == 'symbol' ? it : String(it); -}; -var exp = function(O){ - $export($export.S, 'Reflect', O); -}; - -module.exports = { - store: store, - map: getOrCreateMetadataMap, - has: ordinaryHasOwnMetadata, - get: ordinaryGetOwnMetadata, - set: ordinaryDefineOwnMetadata, - keys: ordinaryOwnMetadataKeys, - key: toMetaKey, - exp: exp -}; - -/***/ }), -/* 27 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -if(__webpack_require__(6)){ - var LIBRARY = __webpack_require__(33) - , global = __webpack_require__(2) - , fails = __webpack_require__(3) - , $export = __webpack_require__(0) - , $typed = __webpack_require__(61) - , $buffer = __webpack_require__(84) - , ctx = __webpack_require__(25) - , anInstance = __webpack_require__(32) - , propertyDesc = __webpack_require__(30) - , hide = __webpack_require__(12) - , redefineAll = __webpack_require__(37) - , toInteger = __webpack_require__(31) - , toLength = __webpack_require__(8) - , toIndex = __webpack_require__(39) - , toPrimitive = __webpack_require__(23) - , has = __webpack_require__(10) - , same = __webpack_require__(110) - , classof = __webpack_require__(48) - , isObject = __webpack_require__(4) - , toObject = __webpack_require__(9) - , isArrayIter = __webpack_require__(69) - , create = __webpack_require__(34) - , getPrototypeOf = __webpack_require__(17) - , gOPN = __webpack_require__(35).f - , getIterFn = __webpack_require__(86) - , uid = __webpack_require__(40) - , wks = __webpack_require__(5) - , createArrayMethod = __webpack_require__(21) - , createArrayIncludes = __webpack_require__(51) - , speciesConstructor = __webpack_require__(78) - , ArrayIterators = __webpack_require__(87) - , Iterators = __webpack_require__(44) - , $iterDetect = __webpack_require__(57) - , setSpecies = __webpack_require__(38) - , arrayFill = __webpack_require__(62) - , arrayCopyWithin = __webpack_require__(90) - , $DP = __webpack_require__(7) - , $GOPD = __webpack_require__(16) - , dP = $DP.f - , gOPD = $GOPD.f - , RangeError = global.RangeError - , TypeError = global.TypeError - , Uint8Array = global.Uint8Array - , ARRAY_BUFFER = 'ArrayBuffer' - , SHARED_BUFFER = 'Shared' + ARRAY_BUFFER - , BYTES_PER_ELEMENT = 'BYTES_PER_ELEMENT' - , PROTOTYPE = 'prototype' - , ArrayProto = Array[PROTOTYPE] - , $ArrayBuffer = $buffer.ArrayBuffer - , $DataView = $buffer.DataView - , arrayForEach = createArrayMethod(0) - , arrayFilter = createArrayMethod(2) - , arraySome = createArrayMethod(3) - , arrayEvery = createArrayMethod(4) - , arrayFind = createArrayMethod(5) - , arrayFindIndex = createArrayMethod(6) - , arrayIncludes = createArrayIncludes(true) - , arrayIndexOf = createArrayIncludes(false) - , arrayValues = ArrayIterators.values - , arrayKeys = ArrayIterators.keys - , arrayEntries = ArrayIterators.entries - , arrayLastIndexOf = ArrayProto.lastIndexOf - , arrayReduce = ArrayProto.reduce - , arrayReduceRight = ArrayProto.reduceRight - , arrayJoin = ArrayProto.join - , arraySort = ArrayProto.sort - , arraySlice = ArrayProto.slice - , arrayToString = ArrayProto.toString - , arrayToLocaleString = ArrayProto.toLocaleString - , ITERATOR = wks('iterator') - , TAG = wks('toStringTag') - , TYPED_CONSTRUCTOR = uid('typed_constructor') - , DEF_CONSTRUCTOR = uid('def_constructor') - , ALL_CONSTRUCTORS = $typed.CONSTR - , TYPED_ARRAY = $typed.TYPED - , VIEW = $typed.VIEW - , WRONG_LENGTH = 'Wrong length!'; - - var $map = createArrayMethod(1, function(O, length){ - return allocate(speciesConstructor(O, O[DEF_CONSTRUCTOR]), length); - }); - - var LITTLE_ENDIAN = fails(function(){ - return new Uint8Array(new Uint16Array([1]).buffer)[0] === 1; - }); - - var FORCED_SET = !!Uint8Array && !!Uint8Array[PROTOTYPE].set && fails(function(){ - new Uint8Array(1).set({}); - }); - - var strictToLength = function(it, SAME){ - if(it === undefined)throw TypeError(WRONG_LENGTH); - var number = +it - , length = toLength(it); - if(SAME && !same(number, length))throw RangeError(WRONG_LENGTH); - return length; - }; - - var toOffset = function(it, BYTES){ - var offset = toInteger(it); - if(offset < 0 || offset % BYTES)throw RangeError('Wrong offset!'); - return offset; - }; - - var validate = function(it){ - if(isObject(it) && TYPED_ARRAY in it)return it; - throw TypeError(it + ' is not a typed array!'); - }; - - var allocate = function(C, length){ - if(!(isObject(C) && TYPED_CONSTRUCTOR in C)){ - throw TypeError('It is not a typed array constructor!'); - } return new C(length); - }; - - var speciesFromList = function(O, list){ - return fromList(speciesConstructor(O, O[DEF_CONSTRUCTOR]), list); - }; - - var fromList = function(C, list){ - var index = 0 - , length = list.length - , result = allocate(C, length); - while(length > index)result[index] = list[index++]; - return result; - }; - - var addGetter = function(it, key, internal){ - dP(it, key, {get: function(){ return this._d[internal]; }}); - }; - - var $from = function from(source /*, mapfn, thisArg */){ - var O = toObject(source) - , aLen = arguments.length - , mapfn = aLen > 1 ? arguments[1] : undefined - , mapping = mapfn !== undefined - , iterFn = getIterFn(O) - , i, length, values, result, step, iterator; - if(iterFn != undefined && !isArrayIter(iterFn)){ - for(iterator = iterFn.call(O), values = [], i = 0; !(step = iterator.next()).done; i++){ - values.push(step.value); - } O = values; - } - if(mapping && aLen > 2)mapfn = ctx(mapfn, arguments[2], 2); - for(i = 0, length = toLength(O.length), result = allocate(this, length); length > i; i++){ - result[i] = mapping ? mapfn(O[i], i) : O[i]; - } - return result; - }; - - var $of = function of(/*...items*/){ - var index = 0 - , length = arguments.length - , result = allocate(this, length); - while(length > index)result[index] = arguments[index++]; - return result; - }; - - // iOS Safari 6.x fails here - var TO_LOCALE_BUG = !!Uint8Array && fails(function(){ arrayToLocaleString.call(new Uint8Array(1)); }); - - var $toLocaleString = function toLocaleString(){ - return arrayToLocaleString.apply(TO_LOCALE_BUG ? arraySlice.call(validate(this)) : validate(this), arguments); - }; - - var proto = { - copyWithin: function copyWithin(target, start /*, end */){ - return arrayCopyWithin.call(validate(this), target, start, arguments.length > 2 ? arguments[2] : undefined); - }, - every: function every(callbackfn /*, thisArg */){ - return arrayEvery(validate(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined); - }, - fill: function fill(value /*, start, end */){ // eslint-disable-line no-unused-vars - return arrayFill.apply(validate(this), arguments); - }, - filter: function filter(callbackfn /*, thisArg */){ - return speciesFromList(this, arrayFilter(validate(this), callbackfn, - arguments.length > 1 ? arguments[1] : undefined)); - }, - find: function find(predicate /*, thisArg */){ - return arrayFind(validate(this), predicate, arguments.length > 1 ? arguments[1] : undefined); - }, - findIndex: function findIndex(predicate /*, thisArg */){ - return arrayFindIndex(validate(this), predicate, arguments.length > 1 ? arguments[1] : undefined); - }, - forEach: function forEach(callbackfn /*, thisArg */){ - arrayForEach(validate(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined); - }, - indexOf: function indexOf(searchElement /*, fromIndex */){ - return arrayIndexOf(validate(this), searchElement, arguments.length > 1 ? arguments[1] : undefined); - }, - includes: function includes(searchElement /*, fromIndex */){ - return arrayIncludes(validate(this), searchElement, arguments.length > 1 ? arguments[1] : undefined); - }, - join: function join(separator){ // eslint-disable-line no-unused-vars - return arrayJoin.apply(validate(this), arguments); - }, - lastIndexOf: function lastIndexOf(searchElement /*, fromIndex */){ // eslint-disable-line no-unused-vars - return arrayLastIndexOf.apply(validate(this), arguments); - }, - map: function map(mapfn /*, thisArg */){ - return $map(validate(this), mapfn, arguments.length > 1 ? arguments[1] : undefined); - }, - reduce: function reduce(callbackfn /*, initialValue */){ // eslint-disable-line no-unused-vars - return arrayReduce.apply(validate(this), arguments); - }, - reduceRight: function reduceRight(callbackfn /*, initialValue */){ // eslint-disable-line no-unused-vars - return arrayReduceRight.apply(validate(this), arguments); - }, - reverse: function reverse(){ - var that = this - , length = validate(that).length - , middle = Math.floor(length / 2) - , index = 0 - , value; - while(index < middle){ - value = that[index]; - that[index++] = that[--length]; - that[length] = value; - } return that; - }, - some: function some(callbackfn /*, thisArg */){ - return arraySome(validate(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined); - }, - sort: function sort(comparefn){ - return arraySort.call(validate(this), comparefn); - }, - subarray: function subarray(begin, end){ - var O = validate(this) - , length = O.length - , $begin = toIndex(begin, length); - return new (speciesConstructor(O, O[DEF_CONSTRUCTOR]))( - O.buffer, - O.byteOffset + $begin * O.BYTES_PER_ELEMENT, - toLength((end === undefined ? length : toIndex(end, length)) - $begin) - ); - } - }; - - var $slice = function slice(start, end){ - return speciesFromList(this, arraySlice.call(validate(this), start, end)); - }; - - var $set = function set(arrayLike /*, offset */){ - validate(this); - var offset = toOffset(arguments[1], 1) - , length = this.length - , src = toObject(arrayLike) - , len = toLength(src.length) - , index = 0; - if(len + offset > length)throw RangeError(WRONG_LENGTH); - while(index < len)this[offset + index] = src[index++]; - }; - - var $iterators = { - entries: function entries(){ - return arrayEntries.call(validate(this)); - }, - keys: function keys(){ - return arrayKeys.call(validate(this)); - }, - values: function values(){ - return arrayValues.call(validate(this)); - } - }; - - var isTAIndex = function(target, key){ - return isObject(target) - && target[TYPED_ARRAY] - && typeof key != 'symbol' - && key in target - && String(+key) == String(key); - }; - var $getDesc = function getOwnPropertyDescriptor(target, key){ - return isTAIndex(target, key = toPrimitive(key, true)) - ? propertyDesc(2, target[key]) - : gOPD(target, key); - }; - var $setDesc = function defineProperty(target, key, desc){ - if(isTAIndex(target, key = toPrimitive(key, true)) - && isObject(desc) - && has(desc, 'value') - && !has(desc, 'get') - && !has(desc, 'set') - // TODO: add validation descriptor w/o calling accessors - && !desc.configurable - && (!has(desc, 'writable') || desc.writable) - && (!has(desc, 'enumerable') || desc.enumerable) - ){ - target[key] = desc.value; - return target; - } else return dP(target, key, desc); - }; - - if(!ALL_CONSTRUCTORS){ - $GOPD.f = $getDesc; - $DP.f = $setDesc; - } - - $export($export.S + $export.F * !ALL_CONSTRUCTORS, 'Object', { - getOwnPropertyDescriptor: $getDesc, - defineProperty: $setDesc - }); - - if(fails(function(){ arrayToString.call({}); })){ - arrayToString = arrayToLocaleString = function toString(){ - return arrayJoin.call(this); - } - } - - var $TypedArrayPrototype$ = redefineAll({}, proto); - redefineAll($TypedArrayPrototype$, $iterators); - hide($TypedArrayPrototype$, ITERATOR, $iterators.values); - redefineAll($TypedArrayPrototype$, { - slice: $slice, - set: $set, - constructor: function(){ /* noop */ }, - toString: arrayToString, - toLocaleString: $toLocaleString - }); - addGetter($TypedArrayPrototype$, 'buffer', 'b'); - addGetter($TypedArrayPrototype$, 'byteOffset', 'o'); - addGetter($TypedArrayPrototype$, 'byteLength', 'l'); - addGetter($TypedArrayPrototype$, 'length', 'e'); - dP($TypedArrayPrototype$, TAG, { - get: function(){ return this[TYPED_ARRAY]; } - }); - - module.exports = function(KEY, BYTES, wrapper, CLAMPED){ - CLAMPED = !!CLAMPED; - var NAME = KEY + (CLAMPED ? 'Clamped' : '') + 'Array' - , ISNT_UINT8 = NAME != 'Uint8Array' - , GETTER = 'get' + KEY - , SETTER = 'set' + KEY - , TypedArray = global[NAME] - , Base = TypedArray || {} - , TAC = TypedArray && getPrototypeOf(TypedArray) - , FORCED = !TypedArray || !$typed.ABV - , O = {} - , TypedArrayPrototype = TypedArray && TypedArray[PROTOTYPE]; - var getter = function(that, index){ - var data = that._d; - return data.v[GETTER](index * BYTES + data.o, LITTLE_ENDIAN); - }; - var setter = function(that, index, value){ - var data = that._d; - if(CLAMPED)value = (value = Math.round(value)) < 0 ? 0 : value > 0xff ? 0xff : value & 0xff; - data.v[SETTER](index * BYTES + data.o, value, LITTLE_ENDIAN); - }; - var addElement = function(that, index){ - dP(that, index, { - get: function(){ - return getter(this, index); - }, - set: function(value){ - return setter(this, index, value); - }, - enumerable: true - }); - }; - if(FORCED){ - TypedArray = wrapper(function(that, data, $offset, $length){ - anInstance(that, TypedArray, NAME, '_d'); - var index = 0 - , offset = 0 - , buffer, byteLength, length, klass; - if(!isObject(data)){ - length = strictToLength(data, true) - byteLength = length * BYTES; - buffer = new $ArrayBuffer(byteLength); - } else if(data instanceof $ArrayBuffer || (klass = classof(data)) == ARRAY_BUFFER || klass == SHARED_BUFFER){ - buffer = data; - offset = toOffset($offset, BYTES); - var $len = data.byteLength; - if($length === undefined){ - if($len % BYTES)throw RangeError(WRONG_LENGTH); - byteLength = $len - offset; - if(byteLength < 0)throw RangeError(WRONG_LENGTH); - } else { - byteLength = toLength($length) * BYTES; - if(byteLength + offset > $len)throw RangeError(WRONG_LENGTH); - } - length = byteLength / BYTES; - } else if(TYPED_ARRAY in data){ - return fromList(TypedArray, data); - } else { - return $from.call(TypedArray, data); - } - hide(that, '_d', { - b: buffer, - o: offset, - l: byteLength, - e: length, - v: new $DataView(buffer) - }); - while(index < length)addElement(that, index++); - }); - TypedArrayPrototype = TypedArray[PROTOTYPE] = create($TypedArrayPrototype$); - hide(TypedArrayPrototype, 'constructor', TypedArray); - } else if(!$iterDetect(function(iter){ - // V8 works with iterators, but fails in many other cases - // https://code.google.com/p/v8/issues/detail?id=4552 - new TypedArray(null); // eslint-disable-line no-new - new TypedArray(iter); // eslint-disable-line no-new - }, true)){ - TypedArray = wrapper(function(that, data, $offset, $length){ - anInstance(that, TypedArray, NAME); - var klass; - // `ws` module bug, temporarily remove validation length for Uint8Array - // https://github.com/websockets/ws/pull/645 - if(!isObject(data))return new Base(strictToLength(data, ISNT_UINT8)); - if(data instanceof $ArrayBuffer || (klass = classof(data)) == ARRAY_BUFFER || klass == SHARED_BUFFER){ - return $length !== undefined - ? new Base(data, toOffset($offset, BYTES), $length) - : $offset !== undefined - ? new Base(data, toOffset($offset, BYTES)) - : new Base(data); - } - if(TYPED_ARRAY in data)return fromList(TypedArray, data); - return $from.call(TypedArray, data); - }); - arrayForEach(TAC !== Function.prototype ? gOPN(Base).concat(gOPN(TAC)) : gOPN(Base), function(key){ - if(!(key in TypedArray))hide(TypedArray, key, Base[key]); - }); - TypedArray[PROTOTYPE] = TypedArrayPrototype; - if(!LIBRARY)TypedArrayPrototype.constructor = TypedArray; - } - var $nativeIterator = TypedArrayPrototype[ITERATOR] - , CORRECT_ITER_NAME = !!$nativeIterator && ($nativeIterator.name == 'values' || $nativeIterator.name == undefined) - , $iterator = $iterators.values; - hide(TypedArray, TYPED_CONSTRUCTOR, true); - hide(TypedArrayPrototype, TYPED_ARRAY, NAME); - hide(TypedArrayPrototype, VIEW, true); - hide(TypedArrayPrototype, DEF_CONSTRUCTOR, TypedArray); - - if(CLAMPED ? new TypedArray(1)[TAG] != NAME : !(TAG in TypedArrayPrototype)){ - dP(TypedArrayPrototype, TAG, { - get: function(){ return NAME; } - }); - } - - O[NAME] = TypedArray; - - $export($export.G + $export.W + $export.F * (TypedArray != Base), O); - - $export($export.S, NAME, { - BYTES_PER_ELEMENT: BYTES, - from: $from, - of: $of - }); - - if(!(BYTES_PER_ELEMENT in TypedArrayPrototype))hide(TypedArrayPrototype, BYTES_PER_ELEMENT, BYTES); - - $export($export.P, NAME, proto); - - setSpecies(NAME); - - $export($export.P + $export.F * FORCED_SET, NAME, {set: $set}); - - $export($export.P + $export.F * !CORRECT_ITER_NAME, NAME, $iterators); - - $export($export.P + $export.F * (TypedArrayPrototype.toString != arrayToString), NAME, {toString: arrayToString}); - - $export($export.P + $export.F * fails(function(){ - new TypedArray(1).slice(); - }), NAME, {slice: $slice}); - - $export($export.P + $export.F * (fails(function(){ - return [1, 2].toLocaleString() != new TypedArray([1, 2]).toLocaleString() - }) || !fails(function(){ - TypedArrayPrototype.toLocaleString.call([1, 2]); - })), NAME, {toLocaleString: $toLocaleString}); - - Iterators[NAME] = CORRECT_ITER_NAME ? $nativeIterator : $iterator; - if(!LIBRARY && !CORRECT_ITER_NAME)hide(TypedArrayPrototype, ITERATOR, $iterator); - }; -} else module.exports = function(){ /* empty */ }; - -/***/ }), -/* 28 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -var className = exports.className = { - WIDGET_BTN: 'widget', - NOTIFICATION: 'notification', - - ACTIVE: 'active', - DISABLED: 'disabled', - - CHANNEL_BOARD: 'channel-board', - BOARD_TOP: 'board-top', - OPTION_MENU: 'option-menu', - OPTION_CONTENT: 'option-content', - - TITLE: 'title', - INPUT: 'input', - BTN: 'btn', - ITEM: 'item', - IMAGE: 'image', - TOP: 'top', - COUNT: 'count', - TIME: 'time', - UNREAD: 'unread', - - CONTENT: 'content', - LOGIN_FORM: 'login-form', - LOGIN_BTN: 'login-btn', - USER_ID: 'user-id', - NICKNAME: 'nickname', - - CHANNEL_LIST: 'channel-list', - CONTENT_TOP: 'content-top', - CONTENT_BOTTOM: 'content-bottom', - LAST_MESSAGE: 'last-message', - EMPTY_ITEM: 'empty-item', - - CHAT_SECTION: 'chat-section', - CHAT_BOARD: 'chat-board', - MESSAGE_CONTENT: 'message-content', - MESSAGE_LIST: 'message-list', - TYPING: 'typing', - TEXT: 'text', - FILE_MESSAGE: 'file-message', - FILE: 'file', - FILE_ICON: 'file-icon', - FILE_NAME: 'file-name', - FILE_DOWNLOAD: 'file-download', - FILE_TEXT: 'file-text', - MESSAGE_SET: 'message-set', - USER: 'user', - MESSAGE_ITEM: 'message-item', - MESSAGE: 'message', - USER_CONTENT: 'user-content', - NEW_CHAT_BTN: 'new-chat-btn', - USER_SELECT: 'user-select', - USER_ITEM: 'user-item', - LEAVE_POPUP: 'leave-popup', - LEAVE_BTN: 'leave-btn', - CANCEL_BTN: 'cancel-btn', - ADMIN_MESSAGE: 'admin-message', - - POPUP: 'popup', - MEMBERS: 'members', - INVITE: 'invite', - POPUP_BODY: 'popup-body', - POPUP_TOP: 'popup-top', - POPUP_CONTENT: 'popup-content', - POPUP_BOTTOM: 'popup-bottom', - INVITE_BTN: 'invite-btn', - IMAGE_ME: 'image-me', - - TOOLTIP: 'tooltip', - - IC_LOGIN: 'ic-login', - IC_CONNECTED: 'ic-connected', - IC_MINIMIZE: 'ic-minimize', - IC_OPTION: 'ic-option', - IC_NEW_CHAT: 'ic-new-chat', - IC_CLOSE: 'ic-close', - IC_MEMBERS: 'ic-members', - IC_INVITE: 'ic-invite', - IC_LEAVE: 'ic-leave', - - FADE_IN: 'sb-fade-in', - FADE_OUT: 'sb-fade-out', - SPINNER: 'sb-spinner' - -}; - -var styleValue = exports.styleValue = { - CURSOR_INIT: '', - CURSOR_DEFAULT: 'default' -}; - -var MAX_COUNT = exports.MAX_COUNT = '+9'; -var MAX_FONT_ZISE = exports.MAX_FONT_ZISE = '11'; - -var TYPE_STRING = exports.TYPE_STRING = 'string'; - -/***/ }), -/* 29 */ -/***/ (function(module, exports, __webpack_require__) { - -var META = __webpack_require__(40)('meta') - , isObject = __webpack_require__(4) - , has = __webpack_require__(10) - , setDesc = __webpack_require__(7).f - , id = 0; -var isExtensible = Object.isExtensible || function(){ - return true; -}; -var FREEZE = !__webpack_require__(3)(function(){ - return isExtensible(Object.preventExtensions({})); -}); -var setMeta = function(it){ - setDesc(it, META, {value: { - i: 'O' + ++id, // object ID - w: {} // weak collections IDs - }}); -}; -var fastKey = function(it, create){ - // return primitive with prefix - if(!isObject(it))return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it; - if(!has(it, META)){ - // can't set metadata to uncaught frozen object - if(!isExtensible(it))return 'F'; - // not necessary to add metadata - if(!create)return 'E'; - // add missing metadata - setMeta(it); - // return object ID - } return it[META].i; -}; -var getWeak = function(it, create){ - if(!has(it, META)){ - // can't set metadata to uncaught frozen object - if(!isExtensible(it))return true; - // not necessary to add metadata - if(!create)return false; - // add missing metadata - setMeta(it); - // return hash weak collections IDs - } return it[META].w; -}; -// add metadata on freeze-family methods calling -var onFreeze = function(it){ - if(FREEZE && meta.NEED && isExtensible(it) && !has(it, META))setMeta(it); - return it; -}; -var meta = module.exports = { - KEY: META, - NEED: false, - fastKey: fastKey, - getWeak: getWeak, - onFreeze: onFreeze -}; - -/***/ }), -/* 30 */ -/***/ (function(module, exports) { - -module.exports = function(bitmap, value){ - return { - enumerable : !(bitmap & 1), - configurable: !(bitmap & 2), - writable : !(bitmap & 4), - value : value - }; -}; - -/***/ }), -/* 31 */ -/***/ (function(module, exports) { - -// 7.1.4 ToInteger -var ceil = Math.ceil - , floor = Math.floor; -module.exports = function(it){ - return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it); -}; - -/***/ }), -/* 32 */ -/***/ (function(module, exports) { - -module.exports = function(it, Constructor, name, forbiddenField){ - if(!(it instanceof Constructor) || (forbiddenField !== undefined && forbiddenField in it)){ - throw TypeError(name + ': incorrect invocation!'); - } return it; -}; - -/***/ }), -/* 33 */ -/***/ (function(module, exports) { - -module.exports = false; - -/***/ }), -/* 34 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties]) -var anObject = __webpack_require__(1) - , dPs = __webpack_require__(103) - , enumBugKeys = __webpack_require__(65) - , IE_PROTO = __webpack_require__(77)('IE_PROTO') - , Empty = function(){ /* empty */ } - , PROTOTYPE = 'prototype'; - -// Create object with fake `null` prototype: use iframe Object with cleared prototype -var createDict = function(){ - // Thrash, waste and sodomy: IE GC bug - var iframe = __webpack_require__(64)('iframe') - , i = enumBugKeys.length - , lt = '<' - , gt = '>' - , iframeDocument; - iframe.style.display = 'none'; - __webpack_require__(67).appendChild(iframe); - iframe.src = 'javascript:'; // eslint-disable-line no-script-url - // createDict = iframe.contentWindow.Object; - // html.removeChild(iframe); - iframeDocument = iframe.contentWindow.document; - iframeDocument.open(); - iframeDocument.write(lt + 'script' + gt + 'document.F=Object' + lt + '/script' + gt); - iframeDocument.close(); - createDict = iframeDocument.F; - while(i--)delete createDict[PROTOTYPE][enumBugKeys[i]]; - return createDict(); -}; - -module.exports = Object.create || function create(O, Properties){ - var result; - if(O !== null){ - Empty[PROTOTYPE] = anObject(O); - result = new Empty; - Empty[PROTOTYPE] = null; - // add "__proto__" for Object.getPrototypeOf polyfill - result[IE_PROTO] = O; - } else result = createDict(); - return Properties === undefined ? result : dPs(result, Properties); -}; - - -/***/ }), -/* 35 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.1.2.7 / 15.2.3.4 Object.getOwnPropertyNames(O) -var $keys = __webpack_require__(105) - , hiddenKeys = __webpack_require__(65).concat('length', 'prototype'); - -exports.f = Object.getOwnPropertyNames || function getOwnPropertyNames(O){ - return $keys(O, hiddenKeys); -}; - -/***/ }), -/* 36 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.1.2.14 / 15.2.3.14 Object.keys(O) -var $keys = __webpack_require__(105) - , enumBugKeys = __webpack_require__(65); - -module.exports = Object.keys || function keys(O){ - return $keys(O, enumBugKeys); -}; - -/***/ }), -/* 37 */ -/***/ (function(module, exports, __webpack_require__) { - -var redefine = __webpack_require__(13); -module.exports = function(target, src, safe){ - for(var key in src)redefine(target, key, src[key], safe); - return target; -}; - -/***/ }), -/* 38 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var global = __webpack_require__(2) - , dP = __webpack_require__(7) - , DESCRIPTORS = __webpack_require__(6) - , SPECIES = __webpack_require__(5)('species'); - -module.exports = function(KEY){ - var C = global[KEY]; - if(DESCRIPTORS && C && !C[SPECIES])dP.f(C, SPECIES, { - configurable: true, - get: function(){ return this; } - }); -}; - -/***/ }), -/* 39 */ -/***/ (function(module, exports, __webpack_require__) { - -var toInteger = __webpack_require__(31) - , max = Math.max - , min = Math.min; -module.exports = function(index, length){ - index = toInteger(index); - return index < 0 ? max(index + length, 0) : min(index, length); -}; - -/***/ }), -/* 40 */ -/***/ (function(module, exports) { - -var id = 0 - , px = Math.random(); -module.exports = function(key){ - return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36)); -}; - -/***/ }), -/* 41 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.hide = hide; -exports.show = show; -exports.hasClass = hasClass; -exports.addClass = addClass; -exports.removeClass = removeClass; -exports.isEmptyString = isEmptyString; -exports.removeWhiteSpace = removeWhiteSpace; -exports.getFullHeight = getFullHeight; -exports.insertMessageInList = insertMessageInList; -exports.getLastItem = getLastItem; -var ANIMATION_EVENT = 'animationend'; -var ANIMATION_REGEX = 'sb-fade.*'; -var DISPLAY_NONE = 'none'; -var DISPLAY_BLOCK = 'block'; - -var hasClassRegex = function hasClassRegex(target, classNameRegex) { - return new RegExp('(^| )' + classNameRegex + '( |$)', 'gi').test(target.className); -}; - -function hide(target) { - if (target) { - if (hasClassRegex(target, ANIMATION_REGEX)) { - var _hideAnimationEvent = void 0; - target.addEventListener(ANIMATION_EVENT, _hideAnimationEvent = function hideAnimationEvent() { - target.style.display = DISPLAY_NONE; - target.removeEventListener(ANIMATION_EVENT, _hideAnimationEvent, false); - }); - } else { - target.style.display = DISPLAY_NONE; - } - } -} - -function show(target, displayType) { - if (target) { - displayType ? target.style.display = displayType : target.style.display = DISPLAY_BLOCK; - } -} - -function hasClass() { - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - return args.reduce(function (target, className) { - if (target.classList) { - return target.classList.contains(className); - } else { - return new RegExp('(^| )' + className + '( |$)', 'gi').test(target.className); - } - }); -} - -function addClass() { - for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - args[_key2] = arguments[_key2]; - } - - return args.reduce(function (target, className) { - if (target.classList) { - if (!(className in target.classList)) { - target.classList.add(className); - } - } else { - if (target.className.indexOf(className) < 0) { - target.className += ' ' + className; - } - } - return target; - }); -} - -function removeClass() { - for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { - args[_key3] = arguments[_key3]; - } - - return args.reduce(function (target, className) { - if (target.classList) { - target.classList.remove(className); - } else { - target.className = target.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ''); - } - return target; - }); -} - -function isEmptyString(target) { - return !!(target == null || target == undefined || target.length == 0); -} - -function removeWhiteSpace(target) { - return target.replace(/ /g, ''); -} - -function getFullHeight(target) { - var height = target.offsetHeight; - var style = getComputedStyle(target); - height += parseInt(style.marginTop) + parseInt(style.marginBottom); - return height; -} - -function insertMessageInList(target, index, item) { - return target.splice(index, 0, item); -} - -function getLastItem(target) { - return target.length < 1 ? null : target[target.length - 1]; -} - -/***/ }), -/* 42 */ -/***/ (function(module, exports, __webpack_require__) { - -// 22.1.3.31 Array.prototype[@@unscopables] -var UNSCOPABLES = __webpack_require__(5)('unscopables') - , ArrayProto = Array.prototype; -if(ArrayProto[UNSCOPABLES] == undefined)__webpack_require__(12)(ArrayProto, UNSCOPABLES, {}); -module.exports = function(key){ - ArrayProto[UNSCOPABLES][key] = true; -}; - -/***/ }), -/* 43 */ -/***/ (function(module, exports, __webpack_require__) { - -var ctx = __webpack_require__(25) - , call = __webpack_require__(99) - , isArrayIter = __webpack_require__(69) - , anObject = __webpack_require__(1) - , toLength = __webpack_require__(8) - , getIterFn = __webpack_require__(86) - , BREAK = {} - , RETURN = {}; -var exports = module.exports = function(iterable, entries, fn, that, ITERATOR){ - var iterFn = ITERATOR ? function(){ return iterable; } : getIterFn(iterable) - , f = ctx(fn, that, entries ? 2 : 1) - , index = 0 - , length, step, iterator, result; - if(typeof iterFn != 'function')throw TypeError(iterable + ' is not iterable!'); - // fast case for arrays with default iterator - if(isArrayIter(iterFn))for(length = toLength(iterable.length); length > index; index++){ - result = entries ? f(anObject(step = iterable[index])[0], step[1]) : f(iterable[index]); - if(result === BREAK || result === RETURN)return result; - } else for(iterator = iterFn.call(iterable); !(step = iterator.next()).done; ){ - result = call(iterator, f, step.value, entries); - if(result === BREAK || result === RETURN)return result; - } -}; -exports.BREAK = BREAK; -exports.RETURN = RETURN; - -/***/ }), -/* 44 */ -/***/ (function(module, exports) { - -module.exports = {}; - -/***/ }), -/* 45 */ -/***/ (function(module, exports, __webpack_require__) { - -var def = __webpack_require__(7).f - , has = __webpack_require__(10) - , TAG = __webpack_require__(5)('toStringTag'); - -module.exports = function(it, tag, stat){ - if(it && !has(it = stat ? it : it.prototype, TAG))def(it, TAG, {configurable: true, value: tag}); -}; - -/***/ }), -/* 46 */ -/***/ (function(module, exports, __webpack_require__) { - -var $export = __webpack_require__(0) - , defined = __webpack_require__(19) - , fails = __webpack_require__(3) - , spaces = __webpack_require__(82) - , space = '[' + spaces + ']' - , non = '\u200b\u0085' - , ltrim = RegExp('^' + space + space + '*') - , rtrim = RegExp(space + space + '*$'); - -var exporter = function(KEY, exec, ALIAS){ - var exp = {}; - var FORCE = fails(function(){ - return !!spaces[KEY]() || non[KEY]() != non; - }); - var fn = exp[KEY] = FORCE ? exec(trim) : spaces[KEY]; - if(ALIAS)exp[ALIAS] = fn; - $export($export.P + $export.F * FORCE, 'String', exp); -}; - -// 1 -> String#trimLeft -// 2 -> String#trimRight -// 3 -> String#trim -var trim = exporter.trim = function(string, TYPE){ - string = String(defined(string)); - if(TYPE & 1)string = string.replace(ltrim, ''); - if(TYPE & 2)string = string.replace(rtrim, ''); - return string; -}; - -module.exports = exporter; - -/***/ }), -/* 47 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = undefined; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -__webpack_require__(315); - -var _utils = __webpack_require__(41); - -var _consts = __webpack_require__(28); - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Element = function () { - function Element() { - _classCallCheck(this, Element); - - this.tagName = { - DIV: 'div', - SPAN: 'span', - INPUT: 'input', - UL: 'ul', - LI: 'li', - TIME: 'time', - LABEL: 'label', - A: 'a', - IMG: 'img' - }; - this.eventName = { - CLICK: 'click', - KEYDOWN: 'keydown', - KEYUP: 'keyup', - CHANGE: 'change', - SCROLL: 'scroll', - PASTE: 'paste' - }; - } - - /* - Create Elements - */ - - - _createClass(Element, [{ - key: 'createDiv', - value: function createDiv() { - return document.createElement(this.tagName.DIV); - } - }, { - key: 'createTime', - value: function createTime() { - return document.createElement(this.tagName.TIME); - } - }, { - key: 'createA', - value: function createA() { - return document.createElement(this.tagName.A); - } - }, { - key: 'createImg', - value: function createImg() { - return document.createElement(this.tagName.IMG); - } - }, { - key: 'createSpan', - value: function createSpan() { - return document.createElement(this.tagName.SPAN); - } - }, { - key: 'createLabel', - value: function createLabel() { - return document.createElement(this.tagName.LABEL); - } - }, { - key: 'createInput', - value: function createInput() { - return document.createElement(this.tagName.INPUT); - } - }, { - key: 'createUl', - value: function createUl() { - return document.createElement(this.tagName.UL); - } - }, { - key: 'createLi', - value: function createLi() { - return document.createElement(this.tagName.LI); - } - }, { - key: '_setClass', - value: function _setClass() { - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - args.reduce(function (target, classes) { - return target.className += classes.join(' '); - }); - } - }, { - key: '_setContent', - value: function _setContent(target, text) { - target.innerHTML = text; - } - }, { - key: '_addContent', - value: function _addContent(target, text) { - target.innerHTML += text; - } - }, { - key: '_setBackgroundImage', - value: function _setBackgroundImage(target, url) { - target.style.backgroundImage = 'url(' + url + ')'; - } - }, { - key: '_setBackgroundSize', - value: function _setBackgroundSize(target, size) { - target.style.backgroundSize = size; - } - }, { - key: '_setFontSize', - value: function _setFontSize(target, size) { - target.style.fontSize = size ? size + 'px' : null; - } - }, { - key: '_setHeight', - value: function _setHeight(target, height) { - target.style.height = height + 'px'; - } - }, { - key: '_setWidth', - value: function _setWidth(target, width) { - target.style.width = width + 'px'; - } - }, { - key: '_setRight', - value: function _setRight(target, right) { - target.style.right = right + 'px'; - } - }, { - key: '_setDataset', - value: function _setDataset(target, name, data) { - target.setAttribute('data-' + name, data); - } - }, { - key: '_setClickEvent', - value: function _setClickEvent() { - var _this = this; - - for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - args[_key2] = arguments[_key2]; - } - - args.reduce(function (target, action) { - target.addEventListener(_this.eventName.CLICK, function () { - action(); - }); - }); - } - }, { - key: '_setPasteEvent', - value: function _setPasteEvent() { - var _this2 = this; - - for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { - args[_key3] = arguments[_key3]; - } - - args.reduce(function (target, action) { - target.addEventListener(_this2.eventName.PASTE, function (event) { - action(event); - }); - }); - } - }, { - key: '_setKeyupEvent', - value: function _setKeyupEvent() { - var _this3 = this; - - for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { - args[_key4] = arguments[_key4]; - } - - args.reduce(function (target, action) { - target.addEventListener(_this3.eventName.KEYUP, function (event) { - action(event); - }); - }); - } - }, { - key: '_setKeydownEvent', - value: function _setKeydownEvent() { - var _this4 = this; - - for (var _len5 = arguments.length, args = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { - args[_key5] = arguments[_key5]; - } - - args.reduce(function (target, action) { - target.addEventListener(_this4.eventName.KEYDOWN, function (event) { - action(event); - }); - }); - } - }, { - key: '_setChangeEvent', - value: function _setChangeEvent() { - var _this5 = this; - - for (var _len6 = arguments.length, args = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { - args[_key6] = arguments[_key6]; - } - - args.reduce(function (target, action) { - target.addEventListener(_this5.eventName.CHANGE, function () { - action(); - }); - }); - } - }, { - key: '_setScrollEvent', - value: function _setScrollEvent() { - var _this6 = this; - - for (var _len7 = arguments.length, args = Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { - args[_key7] = arguments[_key7]; - } - - args.reduce(function (target, action) { - target.addEventListener(_this6.eventName.SCROLL, function () { - action(); - }); - }); - } - }, { - key: '_isBottom', - value: function _isBottom(target, list) { - return target.scrollTop + target.offsetHeight >= list.offsetHeight; - } - }, { - key: 'enabledToggle', - value: function enabledToggle(target, isEnabled) { - if (isEnabled || isEnabled === undefined) { - (0, _utils.removeClass)(target, _consts.className.DISABLED); - target.style.cursor = _consts.styleValue.CURSOR_INIT; - } else { - (0, _utils.addClass)(target, _consts.className.DISABLED); - target.style.cursor = _consts.styleValue.CURSOR_DEFAULT; - } - } - }]); - - return Element; -}(); - -exports.default = Element; - -/***/ }), -/* 48 */ -/***/ (function(module, exports, __webpack_require__) { - -// getting tag from 19.1.3.6 Object.prototype.toString() -var cof = __webpack_require__(18) - , TAG = __webpack_require__(5)('toStringTag') - // ES3 wrong here - , ARG = cof(function(){ return arguments; }()) == 'Arguments'; - -// fallback for IE11 Script Access Denied error -var tryGet = function(it, key){ - try { - return it[key]; - } catch(e){ /* empty */ } -}; - -module.exports = function(it){ - var O, T, B; - return it === undefined ? 'Undefined' : it === null ? 'Null' - // @@toStringTag case - : typeof (T = tryGet(O = Object(it), TAG)) == 'string' ? T - // builtinTag case - : ARG ? cof(O) - // ES3 arguments fallback - : (B = cof(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : B; -}; - -/***/ }), -/* 49 */ -/***/ (function(module, exports, __webpack_require__) { - -// fallback for non-array-like ES3 and non-enumerable old V8 strings -var cof = __webpack_require__(18); -module.exports = Object('z').propertyIsEnumerable(0) ? Object : function(it){ - return cof(it) == 'String' ? it.split('') : Object(it); -}; - -/***/ }), -/* 50 */ -/***/ (function(module, exports) { - -exports.f = {}.propertyIsEnumerable; - -/***/ }), -/* 51 */ -/***/ (function(module, exports, __webpack_require__) { - -// false -> Array#indexOf -// true -> Array#includes -var toIObject = __webpack_require__(15) - , toLength = __webpack_require__(8) - , toIndex = __webpack_require__(39); -module.exports = function(IS_INCLUDES){ - return function($this, el, fromIndex){ - var O = toIObject($this) - , length = toLength(O.length) - , index = toIndex(fromIndex, length) - , value; - // Array#includes uses SameValueZero equality algorithm - if(IS_INCLUDES && el != el)while(length > index){ - value = O[index++]; - if(value != value)return true; - // Array#toIndex ignores holes, Array#includes - not - } else for(;length > index; index++)if(IS_INCLUDES || index in O){ - if(O[index] === el)return IS_INCLUDES || index || 0; - } return !IS_INCLUDES && -1; - }; -}; - -/***/ }), -/* 52 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var global = __webpack_require__(2) - , $export = __webpack_require__(0) - , redefine = __webpack_require__(13) - , redefineAll = __webpack_require__(37) - , meta = __webpack_require__(29) - , forOf = __webpack_require__(43) - , anInstance = __webpack_require__(32) - , isObject = __webpack_require__(4) - , fails = __webpack_require__(3) - , $iterDetect = __webpack_require__(57) - , setToStringTag = __webpack_require__(45) - , inheritIfRequired = __webpack_require__(68); - -module.exports = function(NAME, wrapper, methods, common, IS_MAP, IS_WEAK){ - var Base = global[NAME] - , C = Base - , ADDER = IS_MAP ? 'set' : 'add' - , proto = C && C.prototype - , O = {}; - var fixMethod = function(KEY){ - var fn = proto[KEY]; - redefine(proto, KEY, - KEY == 'delete' ? function(a){ - return IS_WEAK && !isObject(a) ? false : fn.call(this, a === 0 ? 0 : a); - } : KEY == 'has' ? function has(a){ - return IS_WEAK && !isObject(a) ? false : fn.call(this, a === 0 ? 0 : a); - } : KEY == 'get' ? function get(a){ - return IS_WEAK && !isObject(a) ? undefined : fn.call(this, a === 0 ? 0 : a); - } : KEY == 'add' ? function add(a){ fn.call(this, a === 0 ? 0 : a); return this; } - : function set(a, b){ fn.call(this, a === 0 ? 0 : a, b); return this; } - ); - }; - if(typeof C != 'function' || !(IS_WEAK || proto.forEach && !fails(function(){ - new C().entries().next(); - }))){ - // create collection constructor - C = common.getConstructor(wrapper, NAME, IS_MAP, ADDER); - redefineAll(C.prototype, methods); - meta.NEED = true; - } else { - var instance = new C - // early implementations not supports chaining - , HASNT_CHAINING = instance[ADDER](IS_WEAK ? {} : -0, 1) != instance - // V8 ~ Chromium 40- weak-collections throws on primitives, but should return false - , THROWS_ON_PRIMITIVES = fails(function(){ instance.has(1); }) - // most early implementations doesn't supports iterables, most modern - not close it correctly - , ACCEPT_ITERABLES = $iterDetect(function(iter){ new C(iter); }) // eslint-disable-line no-new - // for early implementations -0 and +0 not the same - , BUGGY_ZERO = !IS_WEAK && fails(function(){ - // V8 ~ Chromium 42- fails only with 5+ elements - var $instance = new C() - , index = 5; - while(index--)$instance[ADDER](index, index); - return !$instance.has(-0); - }); - if(!ACCEPT_ITERABLES){ - C = wrapper(function(target, iterable){ - anInstance(target, C, NAME); - var that = inheritIfRequired(new Base, target, C); - if(iterable != undefined)forOf(iterable, IS_MAP, that[ADDER], that); - return that; - }); - C.prototype = proto; - proto.constructor = C; - } - if(THROWS_ON_PRIMITIVES || BUGGY_ZERO){ - fixMethod('delete'); - fixMethod('has'); - IS_MAP && fixMethod('get'); - } - if(BUGGY_ZERO || HASNT_CHAINING)fixMethod(ADDER); - // weak collections should not contains .clear method - if(IS_WEAK && proto.clear)delete proto.clear; - } - - setToStringTag(C, NAME); - - O[NAME] = C; - $export($export.G + $export.W + $export.F * (C != Base), O); - - if(!IS_WEAK)common.setStrong(C, NAME, IS_MAP); - - return C; -}; - -/***/ }), -/* 53 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var hide = __webpack_require__(12) - , redefine = __webpack_require__(13) - , fails = __webpack_require__(3) - , defined = __webpack_require__(19) - , wks = __webpack_require__(5); - -module.exports = function(KEY, length, exec){ - var SYMBOL = wks(KEY) - , fns = exec(defined, SYMBOL, ''[KEY]) - , strfn = fns[0] - , rxfn = fns[1]; - if(fails(function(){ - var O = {}; - O[SYMBOL] = function(){ return 7; }; - return ''[KEY](O) != 7; - })){ - redefine(String.prototype, KEY, strfn); - hide(RegExp.prototype, SYMBOL, length == 2 - // 21.2.5.8 RegExp.prototype[@@replace](string, replaceValue) - // 21.2.5.11 RegExp.prototype[@@split](string, limit) - ? function(string, arg){ return rxfn.call(string, this, arg); } - // 21.2.5.6 RegExp.prototype[@@match](string) - // 21.2.5.9 RegExp.prototype[@@search](string) - : function(string){ return rxfn.call(string, this); } - ); - } -}; - -/***/ }), -/* 54 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// 21.2.5.3 get RegExp.prototype.flags -var anObject = __webpack_require__(1); -module.exports = function(){ - var that = anObject(this) - , result = ''; - if(that.global) result += 'g'; - if(that.ignoreCase) result += 'i'; - if(that.multiline) result += 'm'; - if(that.unicode) result += 'u'; - if(that.sticky) result += 'y'; - return result; -}; - -/***/ }), -/* 55 */ -/***/ (function(module, exports) { - -// fast apply, http://jsperf.lnkit.com/fast-apply/5 -module.exports = function(fn, args, that){ - var un = that === undefined; - switch(args.length){ - case 0: return un ? fn() - : fn.call(that); - case 1: return un ? fn(args[0]) - : fn.call(that, args[0]); - case 2: return un ? fn(args[0], args[1]) - : fn.call(that, args[0], args[1]); - case 3: return un ? fn(args[0], args[1], args[2]) - : fn.call(that, args[0], args[1], args[2]); - case 4: return un ? fn(args[0], args[1], args[2], args[3]) - : fn.call(that, args[0], args[1], args[2], args[3]); - } return fn.apply(that, args); -}; - -/***/ }), -/* 56 */ -/***/ (function(module, exports, __webpack_require__) { - -// 7.2.8 IsRegExp(argument) -var isObject = __webpack_require__(4) - , cof = __webpack_require__(18) - , MATCH = __webpack_require__(5)('match'); -module.exports = function(it){ - var isRegExp; - return isObject(it) && ((isRegExp = it[MATCH]) !== undefined ? !!isRegExp : cof(it) == 'RegExp'); -}; - -/***/ }), -/* 57 */ -/***/ (function(module, exports, __webpack_require__) { - -var ITERATOR = __webpack_require__(5)('iterator') - , SAFE_CLOSING = false; - -try { - var riter = [7][ITERATOR](); - riter['return'] = function(){ SAFE_CLOSING = true; }; - Array.from(riter, function(){ throw 2; }); -} catch(e){ /* empty */ } - -module.exports = function(exec, skipClosing){ - if(!skipClosing && !SAFE_CLOSING)return false; - var safe = false; - try { - var arr = [7] - , iter = arr[ITERATOR](); - iter.next = function(){ return {done: safe = true}; }; - arr[ITERATOR] = function(){ return iter; }; - exec(arr); - } catch(e){ /* empty */ } - return safe; -}; - -/***/ }), -/* 58 */ -/***/ (function(module, exports, __webpack_require__) { - -// Forced replacement prototype accessors methods -module.exports = __webpack_require__(33)|| !__webpack_require__(3)(function(){ - var K = Math.random(); - // In FF throws only define methods - __defineSetter__.call(null, K, function(){ /* empty */}); - delete __webpack_require__(2)[K]; -}); - -/***/ }), -/* 59 */ -/***/ (function(module, exports) { - -exports.f = Object.getOwnPropertySymbols; - -/***/ }), -/* 60 */ -/***/ (function(module, exports, __webpack_require__) { - -var global = __webpack_require__(2) - , SHARED = '__core-js_shared__' - , store = global[SHARED] || (global[SHARED] = {}); -module.exports = function(key){ - return store[key] || (store[key] = {}); -}; - -/***/ }), -/* 61 */ -/***/ (function(module, exports, __webpack_require__) { - -var global = __webpack_require__(2) - , hide = __webpack_require__(12) - , uid = __webpack_require__(40) - , TYPED = uid('typed_array') - , VIEW = uid('view') - , ABV = !!(global.ArrayBuffer && global.DataView) - , CONSTR = ABV - , i = 0, l = 9, Typed; - -var TypedArrayConstructors = ( - 'Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array' -).split(','); - -while(i < l){ - if(Typed = global[TypedArrayConstructors[i++]]){ - hide(Typed.prototype, TYPED, true); - hide(Typed.prototype, VIEW, true); - } else CONSTR = false; -} - -module.exports = { - ABV: ABV, - CONSTR: CONSTR, - TYPED: TYPED, - VIEW: VIEW -}; - -/***/ }), -/* 62 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -// 22.1.3.6 Array.prototype.fill(value, start = 0, end = this.length) - -var toObject = __webpack_require__(9) - , toIndex = __webpack_require__(39) - , toLength = __webpack_require__(8); -module.exports = function fill(value /*, start = 0, end = @length */){ - var O = toObject(this) - , length = toLength(O.length) - , aLen = arguments.length - , index = toIndex(aLen > 1 ? arguments[1] : undefined, length) - , end = aLen > 2 ? arguments[2] : undefined - , endPos = end === undefined ? length : toIndex(end, length); - while(endPos > index)O[index++] = value; - return O; -}; - -/***/ }), -/* 63 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $defineProperty = __webpack_require__(7) - , createDesc = __webpack_require__(30); - -module.exports = function(object, index, value){ - if(index in object)$defineProperty.f(object, index, createDesc(0, value)); - else object[index] = value; -}; - -/***/ }), -/* 64 */ -/***/ (function(module, exports, __webpack_require__) { - -var isObject = __webpack_require__(4) - , document = __webpack_require__(2).document - // in old IE typeof document.createElement is 'object' - , is = isObject(document) && isObject(document.createElement); -module.exports = function(it){ - return is ? document.createElement(it) : {}; -}; - -/***/ }), -/* 65 */ -/***/ (function(module, exports) { - -// IE 8- don't enum bug keys -module.exports = ( - 'constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf' -).split(','); - -/***/ }), -/* 66 */ -/***/ (function(module, exports, __webpack_require__) { - -var MATCH = __webpack_require__(5)('match'); -module.exports = function(KEY){ - var re = /./; - try { - '/./'[KEY](re); - } catch(e){ - try { - re[MATCH] = false; - return !'/./'[KEY](re); - } catch(f){ /* empty */ } - } return true; -}; - -/***/ }), -/* 67 */ -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__(2).document && document.documentElement; - -/***/ }), -/* 68 */ -/***/ (function(module, exports, __webpack_require__) { - -var isObject = __webpack_require__(4) - , setPrototypeOf = __webpack_require__(76).set; -module.exports = function(that, target, C){ - var P, S = target.constructor; - if(S !== C && typeof S == 'function' && (P = S.prototype) !== C.prototype && isObject(P) && setPrototypeOf){ - setPrototypeOf(that, P); - } return that; -}; - -/***/ }), -/* 69 */ -/***/ (function(module, exports, __webpack_require__) { - -// check on default Array iterator -var Iterators = __webpack_require__(44) - , ITERATOR = __webpack_require__(5)('iterator') - , ArrayProto = Array.prototype; - -module.exports = function(it){ - return it !== undefined && (Iterators.Array === it || ArrayProto[ITERATOR] === it); -}; - -/***/ }), -/* 70 */ -/***/ (function(module, exports, __webpack_require__) { - -// 7.2.2 IsArray(argument) -var cof = __webpack_require__(18); -module.exports = Array.isArray || function isArray(arg){ - return cof(arg) == 'Array'; -}; - -/***/ }), -/* 71 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var create = __webpack_require__(34) - , descriptor = __webpack_require__(30) - , setToStringTag = __webpack_require__(45) - , IteratorPrototype = {}; - -// 25.1.2.1.1 %IteratorPrototype%[@@iterator]() -__webpack_require__(12)(IteratorPrototype, __webpack_require__(5)('iterator'), function(){ return this; }); - -module.exports = function(Constructor, NAME, next){ - Constructor.prototype = create(IteratorPrototype, {next: descriptor(1, next)}); - setToStringTag(Constructor, NAME + ' Iterator'); -}; - -/***/ }), -/* 72 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var LIBRARY = __webpack_require__(33) - , $export = __webpack_require__(0) - , redefine = __webpack_require__(13) - , hide = __webpack_require__(12) - , has = __webpack_require__(10) - , Iterators = __webpack_require__(44) - , $iterCreate = __webpack_require__(71) - , setToStringTag = __webpack_require__(45) - , getPrototypeOf = __webpack_require__(17) - , ITERATOR = __webpack_require__(5)('iterator') - , BUGGY = !([].keys && 'next' in [].keys()) // Safari has buggy iterators w/o `next` - , FF_ITERATOR = '@@iterator' - , KEYS = 'keys' - , VALUES = 'values'; - -var returnThis = function(){ return this; }; - -module.exports = function(Base, NAME, Constructor, next, DEFAULT, IS_SET, FORCED){ - $iterCreate(Constructor, NAME, next); - var getMethod = function(kind){ - if(!BUGGY && kind in proto)return proto[kind]; - switch(kind){ - case KEYS: return function keys(){ return new Constructor(this, kind); }; - case VALUES: return function values(){ return new Constructor(this, kind); }; - } return function entries(){ return new Constructor(this, kind); }; - }; - var TAG = NAME + ' Iterator' - , DEF_VALUES = DEFAULT == VALUES - , VALUES_BUG = false - , proto = Base.prototype - , $native = proto[ITERATOR] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT] - , $default = $native || getMethod(DEFAULT) - , $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined - , $anyNative = NAME == 'Array' ? proto.entries || $native : $native - , methods, key, IteratorPrototype; - // Fix native - if($anyNative){ - IteratorPrototype = getPrototypeOf($anyNative.call(new Base)); - if(IteratorPrototype !== Object.prototype){ - // Set @@toStringTag to native iterators - setToStringTag(IteratorPrototype, TAG, true); - // fix for some old engines - if(!LIBRARY && !has(IteratorPrototype, ITERATOR))hide(IteratorPrototype, ITERATOR, returnThis); - } - } - // fix Array#{values, @@iterator}.name in V8 / FF - if(DEF_VALUES && $native && $native.name !== VALUES){ - VALUES_BUG = true; - $default = function values(){ return $native.call(this); }; - } - // Define iterator - if((!LIBRARY || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR])){ - hide(proto, ITERATOR, $default); - } - // Plug for library - Iterators[NAME] = $default; - Iterators[TAG] = returnThis; - if(DEFAULT){ - methods = { - values: DEF_VALUES ? $default : getMethod(VALUES), - keys: IS_SET ? $default : getMethod(KEYS), - entries: $entries - }; - if(FORCED)for(key in methods){ - if(!(key in proto))redefine(proto, key, methods[key]); - } else $export($export.P + $export.F * (BUGGY || VALUES_BUG), NAME, methods); - } - return methods; -}; - -/***/ }), -/* 73 */ -/***/ (function(module, exports) { - -// 20.2.2.14 Math.expm1(x) -var $expm1 = Math.expm1; -module.exports = (!$expm1 - // Old FF bug - || $expm1(10) > 22025.465794806719 || $expm1(10) < 22025.4657948067165168 - // Tor Browser bug - || $expm1(-2e-17) != -2e-17 -) ? function expm1(x){ - return (x = +x) == 0 ? x : x > -1e-6 && x < 1e-6 ? x + x * x / 2 : Math.exp(x) - 1; -} : $expm1; - -/***/ }), -/* 74 */ -/***/ (function(module, exports) { - -// 20.2.2.28 Math.sign(x) -module.exports = Math.sign || function sign(x){ - return (x = +x) == 0 || x != x ? x : x < 0 ? -1 : 1; -}; - -/***/ }), -/* 75 */ -/***/ (function(module, exports, __webpack_require__) { - -var global = __webpack_require__(2) - , macrotask = __webpack_require__(83).set - , Observer = global.MutationObserver || global.WebKitMutationObserver - , process = global.process - , Promise = global.Promise - , isNode = __webpack_require__(18)(process) == 'process'; - -module.exports = function(){ - var head, last, notify; - - var flush = function(){ - var parent, fn; - if(isNode && (parent = process.domain))parent.exit(); - while(head){ - fn = head.fn; - head = head.next; - try { - fn(); - } catch(e){ - if(head)notify(); - else last = undefined; - throw e; - } - } last = undefined; - if(parent)parent.enter(); - }; - - // Node.js - if(isNode){ - notify = function(){ - process.nextTick(flush); - }; - // browsers with MutationObserver - } else if(Observer){ - var toggle = true - , node = document.createTextNode(''); - new Observer(flush).observe(node, {characterData: true}); // eslint-disable-line no-new - notify = function(){ - node.data = toggle = !toggle; - }; - // environments with maybe non-completely correct, but existent Promise - } else if(Promise && Promise.resolve){ - var promise = Promise.resolve(); - notify = function(){ - promise.then(flush); - }; - // for other environments - macrotask based on: - // - setImmediate - // - MessageChannel - // - window.postMessag - // - onreadystatechange - // - setTimeout - } else { - notify = function(){ - // strange IE + webpack dev server bug - use .call(global) - macrotask.call(global, flush); - }; - } - - return function(fn){ - var task = {fn: fn, next: undefined}; - if(last)last.next = task; - if(!head){ - head = task; - notify(); - } last = task; - }; -}; - -/***/ }), -/* 76 */ -/***/ (function(module, exports, __webpack_require__) { - -// Works with __proto__ only. Old v8 can't work with null proto objects. -/* eslint-disable no-proto */ -var isObject = __webpack_require__(4) - , anObject = __webpack_require__(1); -var check = function(O, proto){ - anObject(O); - if(!isObject(proto) && proto !== null)throw TypeError(proto + ": can't set as prototype!"); -}; -module.exports = { - set: Object.setPrototypeOf || ('__proto__' in {} ? // eslint-disable-line - function(test, buggy, set){ - try { - set = __webpack_require__(25)(Function.call, __webpack_require__(16).f(Object.prototype, '__proto__').set, 2); - set(test, []); - buggy = !(test instanceof Array); - } catch(e){ buggy = true; } - return function setPrototypeOf(O, proto){ - check(O, proto); - if(buggy)O.__proto__ = proto; - else set(O, proto); - return O; - }; - }({}, false) : undefined), - check: check -}; - -/***/ }), -/* 77 */ -/***/ (function(module, exports, __webpack_require__) { - -var shared = __webpack_require__(60)('keys') - , uid = __webpack_require__(40); -module.exports = function(key){ - return shared[key] || (shared[key] = uid(key)); -}; - -/***/ }), -/* 78 */ -/***/ (function(module, exports, __webpack_require__) { - -// 7.3.20 SpeciesConstructor(O, defaultConstructor) -var anObject = __webpack_require__(1) - , aFunction = __webpack_require__(11) - , SPECIES = __webpack_require__(5)('species'); -module.exports = function(O, D){ - var C = anObject(O).constructor, S; - return C === undefined || (S = anObject(C)[SPECIES]) == undefined ? D : aFunction(S); -}; - -/***/ }), -/* 79 */ -/***/ (function(module, exports, __webpack_require__) { - -var toInteger = __webpack_require__(31) - , defined = __webpack_require__(19); -// true -> String#at -// false -> String#codePointAt -module.exports = function(TO_STRING){ - return function(that, pos){ - var s = String(defined(that)) - , i = toInteger(pos) - , l = s.length - , a, b; - if(i < 0 || i >= l)return TO_STRING ? '' : undefined; - a = s.charCodeAt(i); - return a < 0xd800 || a > 0xdbff || i + 1 === l || (b = s.charCodeAt(i + 1)) < 0xdc00 || b > 0xdfff - ? TO_STRING ? s.charAt(i) : a - : TO_STRING ? s.slice(i, i + 2) : (a - 0xd800 << 10) + (b - 0xdc00) + 0x10000; - }; -}; - -/***/ }), -/* 80 */ -/***/ (function(module, exports, __webpack_require__) { - -// helper for String#{startsWith, endsWith, includes} -var isRegExp = __webpack_require__(56) - , defined = __webpack_require__(19); - -module.exports = function(that, searchString, NAME){ - if(isRegExp(searchString))throw TypeError('String#' + NAME + " doesn't accept regex!"); - return String(defined(that)); -}; - -/***/ }), -/* 81 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var toInteger = __webpack_require__(31) - , defined = __webpack_require__(19); - -module.exports = function repeat(count){ - var str = String(defined(this)) - , res = '' - , n = toInteger(count); - if(n < 0 || n == Infinity)throw RangeError("Count can't be negative"); - for(;n > 0; (n >>>= 1) && (str += str))if(n & 1)res += str; - return res; -}; - -/***/ }), -/* 82 */ -/***/ (function(module, exports) { - -module.exports = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003' + - '\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF'; - -/***/ }), -/* 83 */ -/***/ (function(module, exports, __webpack_require__) { - -var ctx = __webpack_require__(25) - , invoke = __webpack_require__(55) - , html = __webpack_require__(67) - , cel = __webpack_require__(64) - , global = __webpack_require__(2) - , process = global.process - , setTask = global.setImmediate - , clearTask = global.clearImmediate - , MessageChannel = global.MessageChannel - , counter = 0 - , queue = {} - , ONREADYSTATECHANGE = 'onreadystatechange' - , defer, channel, port; -var run = function(){ - var id = +this; - if(queue.hasOwnProperty(id)){ - var fn = queue[id]; - delete queue[id]; - fn(); - } -}; -var listener = function(event){ - run.call(event.data); -}; -// Node.js 0.9+ & IE10+ has setImmediate, otherwise: -if(!setTask || !clearTask){ - setTask = function setImmediate(fn){ - var args = [], i = 1; - while(arguments.length > i)args.push(arguments[i++]); - queue[++counter] = function(){ - invoke(typeof fn == 'function' ? fn : Function(fn), args); - }; - defer(counter); - return counter; - }; - clearTask = function clearImmediate(id){ - delete queue[id]; - }; - // Node.js 0.8- - if(__webpack_require__(18)(process) == 'process'){ - defer = function(id){ - process.nextTick(ctx(run, id, 1)); - }; - // Browsers with MessageChannel, includes WebWorkers - } else if(MessageChannel){ - channel = new MessageChannel; - port = channel.port2; - channel.port1.onmessage = listener; - defer = ctx(port.postMessage, port, 1); - // Browsers with postMessage, skip WebWorkers - // IE8 has postMessage, but it's sync & typeof its postMessage is 'object' - } else if(global.addEventListener && typeof postMessage == 'function' && !global.importScripts){ - defer = function(id){ - global.postMessage(id + '', '*'); - }; - global.addEventListener('message', listener, false); - // IE8- - } else if(ONREADYSTATECHANGE in cel('script')){ - defer = function(id){ - html.appendChild(cel('script'))[ONREADYSTATECHANGE] = function(){ - html.removeChild(this); - run.call(id); - }; - }; - // Rest old browsers - } else { - defer = function(id){ - setTimeout(ctx(run, id, 1), 0); - }; - } -} -module.exports = { - set: setTask, - clear: clearTask -}; - -/***/ }), -/* 84 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var global = __webpack_require__(2) - , DESCRIPTORS = __webpack_require__(6) - , LIBRARY = __webpack_require__(33) - , $typed = __webpack_require__(61) - , hide = __webpack_require__(12) - , redefineAll = __webpack_require__(37) - , fails = __webpack_require__(3) - , anInstance = __webpack_require__(32) - , toInteger = __webpack_require__(31) - , toLength = __webpack_require__(8) - , gOPN = __webpack_require__(35).f - , dP = __webpack_require__(7).f - , arrayFill = __webpack_require__(62) - , setToStringTag = __webpack_require__(45) - , ARRAY_BUFFER = 'ArrayBuffer' - , DATA_VIEW = 'DataView' - , PROTOTYPE = 'prototype' - , WRONG_LENGTH = 'Wrong length!' - , WRONG_INDEX = 'Wrong index!' - , $ArrayBuffer = global[ARRAY_BUFFER] - , $DataView = global[DATA_VIEW] - , Math = global.Math - , RangeError = global.RangeError - , Infinity = global.Infinity - , BaseBuffer = $ArrayBuffer - , abs = Math.abs - , pow = Math.pow - , floor = Math.floor - , log = Math.log - , LN2 = Math.LN2 - , BUFFER = 'buffer' - , BYTE_LENGTH = 'byteLength' - , BYTE_OFFSET = 'byteOffset' - , $BUFFER = DESCRIPTORS ? '_b' : BUFFER - , $LENGTH = DESCRIPTORS ? '_l' : BYTE_LENGTH - , $OFFSET = DESCRIPTORS ? '_o' : BYTE_OFFSET; - -// IEEE754 conversions based on https://github.com/feross/ieee754 -var packIEEE754 = function(value, mLen, nBytes){ - var buffer = Array(nBytes) - , eLen = nBytes * 8 - mLen - 1 - , eMax = (1 << eLen) - 1 - , eBias = eMax >> 1 - , rt = mLen === 23 ? pow(2, -24) - pow(2, -77) : 0 - , i = 0 - , s = value < 0 || value === 0 && 1 / value < 0 ? 1 : 0 - , e, m, c; - value = abs(value) - if(value != value || value === Infinity){ - m = value != value ? 1 : 0; - e = eMax; - } else { - e = floor(log(value) / LN2); - if(value * (c = pow(2, -e)) < 1){ - e--; - c *= 2; - } - if(e + eBias >= 1){ - value += rt / c; - } else { - value += rt * pow(2, 1 - eBias); - } - if(value * c >= 2){ - e++; - c /= 2; - } - if(e + eBias >= eMax){ - m = 0; - e = eMax; - } else if(e + eBias >= 1){ - m = (value * c - 1) * pow(2, mLen); - e = e + eBias; - } else { - m = value * pow(2, eBias - 1) * pow(2, mLen); - e = 0; - } - } - for(; mLen >= 8; buffer[i++] = m & 255, m /= 256, mLen -= 8); - e = e << mLen | m; - eLen += mLen; - for(; eLen > 0; buffer[i++] = e & 255, e /= 256, eLen -= 8); - buffer[--i] |= s * 128; - return buffer; -}; -var unpackIEEE754 = function(buffer, mLen, nBytes){ - var eLen = nBytes * 8 - mLen - 1 - , eMax = (1 << eLen) - 1 - , eBias = eMax >> 1 - , nBits = eLen - 7 - , i = nBytes - 1 - , s = buffer[i--] - , e = s & 127 - , m; - s >>= 7; - for(; nBits > 0; e = e * 256 + buffer[i], i--, nBits -= 8); - m = e & (1 << -nBits) - 1; - e >>= -nBits; - nBits += mLen; - for(; nBits > 0; m = m * 256 + buffer[i], i--, nBits -= 8); - if(e === 0){ - e = 1 - eBias; - } else if(e === eMax){ - return m ? NaN : s ? -Infinity : Infinity; - } else { - m = m + pow(2, mLen); - e = e - eBias; - } return (s ? -1 : 1) * m * pow(2, e - mLen); -}; - -var unpackI32 = function(bytes){ - return bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0]; -}; -var packI8 = function(it){ - return [it & 0xff]; -}; -var packI16 = function(it){ - return [it & 0xff, it >> 8 & 0xff]; -}; -var packI32 = function(it){ - return [it & 0xff, it >> 8 & 0xff, it >> 16 & 0xff, it >> 24 & 0xff]; -}; -var packF64 = function(it){ - return packIEEE754(it, 52, 8); -}; -var packF32 = function(it){ - return packIEEE754(it, 23, 4); -}; - -var addGetter = function(C, key, internal){ - dP(C[PROTOTYPE], key, {get: function(){ return this[internal]; }}); -}; - -var get = function(view, bytes, index, isLittleEndian){ - var numIndex = +index - , intIndex = toInteger(numIndex); - if(numIndex != intIndex || intIndex < 0 || intIndex + bytes > view[$LENGTH])throw RangeError(WRONG_INDEX); - var store = view[$BUFFER]._b - , start = intIndex + view[$OFFSET] - , pack = store.slice(start, start + bytes); - return isLittleEndian ? pack : pack.reverse(); -}; -var set = function(view, bytes, index, conversion, value, isLittleEndian){ - var numIndex = +index - , intIndex = toInteger(numIndex); - if(numIndex != intIndex || intIndex < 0 || intIndex + bytes > view[$LENGTH])throw RangeError(WRONG_INDEX); - var store = view[$BUFFER]._b - , start = intIndex + view[$OFFSET] - , pack = conversion(+value); - for(var i = 0; i < bytes; i++)store[start + i] = pack[isLittleEndian ? i : bytes - i - 1]; -}; - -var validateArrayBufferArguments = function(that, length){ - anInstance(that, $ArrayBuffer, ARRAY_BUFFER); - var numberLength = +length - , byteLength = toLength(numberLength); - if(numberLength != byteLength)throw RangeError(WRONG_LENGTH); - return byteLength; -}; - -if(!$typed.ABV){ - $ArrayBuffer = function ArrayBuffer(length){ - var byteLength = validateArrayBufferArguments(this, length); - this._b = arrayFill.call(Array(byteLength), 0); - this[$LENGTH] = byteLength; - }; - - $DataView = function DataView(buffer, byteOffset, byteLength){ - anInstance(this, $DataView, DATA_VIEW); - anInstance(buffer, $ArrayBuffer, DATA_VIEW); - var bufferLength = buffer[$LENGTH] - , offset = toInteger(byteOffset); - if(offset < 0 || offset > bufferLength)throw RangeError('Wrong offset!'); - byteLength = byteLength === undefined ? bufferLength - offset : toLength(byteLength); - if(offset + byteLength > bufferLength)throw RangeError(WRONG_LENGTH); - this[$BUFFER] = buffer; - this[$OFFSET] = offset; - this[$LENGTH] = byteLength; - }; - - if(DESCRIPTORS){ - addGetter($ArrayBuffer, BYTE_LENGTH, '_l'); - addGetter($DataView, BUFFER, '_b'); - addGetter($DataView, BYTE_LENGTH, '_l'); - addGetter($DataView, BYTE_OFFSET, '_o'); - } - - redefineAll($DataView[PROTOTYPE], { - getInt8: function getInt8(byteOffset){ - return get(this, 1, byteOffset)[0] << 24 >> 24; - }, - getUint8: function getUint8(byteOffset){ - return get(this, 1, byteOffset)[0]; - }, - getInt16: function getInt16(byteOffset /*, littleEndian */){ - var bytes = get(this, 2, byteOffset, arguments[1]); - return (bytes[1] << 8 | bytes[0]) << 16 >> 16; - }, - getUint16: function getUint16(byteOffset /*, littleEndian */){ - var bytes = get(this, 2, byteOffset, arguments[1]); - return bytes[1] << 8 | bytes[0]; - }, - getInt32: function getInt32(byteOffset /*, littleEndian */){ - return unpackI32(get(this, 4, byteOffset, arguments[1])); - }, - getUint32: function getUint32(byteOffset /*, littleEndian */){ - return unpackI32(get(this, 4, byteOffset, arguments[1])) >>> 0; - }, - getFloat32: function getFloat32(byteOffset /*, littleEndian */){ - return unpackIEEE754(get(this, 4, byteOffset, arguments[1]), 23, 4); - }, - getFloat64: function getFloat64(byteOffset /*, littleEndian */){ - return unpackIEEE754(get(this, 8, byteOffset, arguments[1]), 52, 8); - }, - setInt8: function setInt8(byteOffset, value){ - set(this, 1, byteOffset, packI8, value); - }, - setUint8: function setUint8(byteOffset, value){ - set(this, 1, byteOffset, packI8, value); - }, - setInt16: function setInt16(byteOffset, value /*, littleEndian */){ - set(this, 2, byteOffset, packI16, value, arguments[2]); - }, - setUint16: function setUint16(byteOffset, value /*, littleEndian */){ - set(this, 2, byteOffset, packI16, value, arguments[2]); - }, - setInt32: function setInt32(byteOffset, value /*, littleEndian */){ - set(this, 4, byteOffset, packI32, value, arguments[2]); - }, - setUint32: function setUint32(byteOffset, value /*, littleEndian */){ - set(this, 4, byteOffset, packI32, value, arguments[2]); - }, - setFloat32: function setFloat32(byteOffset, value /*, littleEndian */){ - set(this, 4, byteOffset, packF32, value, arguments[2]); - }, - setFloat64: function setFloat64(byteOffset, value /*, littleEndian */){ - set(this, 8, byteOffset, packF64, value, arguments[2]); - } - }); -} else { - if(!fails(function(){ - new $ArrayBuffer; // eslint-disable-line no-new - }) || !fails(function(){ - new $ArrayBuffer(.5); // eslint-disable-line no-new - })){ - $ArrayBuffer = function ArrayBuffer(length){ - return new BaseBuffer(validateArrayBufferArguments(this, length)); - }; - var ArrayBufferProto = $ArrayBuffer[PROTOTYPE] = BaseBuffer[PROTOTYPE]; - for(var keys = gOPN(BaseBuffer), j = 0, key; keys.length > j; ){ - if(!((key = keys[j++]) in $ArrayBuffer))hide($ArrayBuffer, key, BaseBuffer[key]); - }; - if(!LIBRARY)ArrayBufferProto.constructor = $ArrayBuffer; - } - // iOS Safari 7.x bug - var view = new $DataView(new $ArrayBuffer(2)) - , $setInt8 = $DataView[PROTOTYPE].setInt8; - view.setInt8(0, 2147483648); - view.setInt8(1, 2147483649); - if(view.getInt8(0) || !view.getInt8(1))redefineAll($DataView[PROTOTYPE], { - setInt8: function setInt8(byteOffset, value){ - $setInt8.call(this, byteOffset, value << 24 >> 24); - }, - setUint8: function setUint8(byteOffset, value){ - $setInt8.call(this, byteOffset, value << 24 >> 24); - } - }, true); -} -setToStringTag($ArrayBuffer, ARRAY_BUFFER); -setToStringTag($DataView, DATA_VIEW); -hide($DataView[PROTOTYPE], $typed.VIEW, true); -exports[ARRAY_BUFFER] = $ArrayBuffer; -exports[DATA_VIEW] = $DataView; - -/***/ }), -/* 85 */ -/***/ (function(module, exports, __webpack_require__) { - -var global = __webpack_require__(2) - , core = __webpack_require__(24) - , LIBRARY = __webpack_require__(33) - , wksExt = __webpack_require__(112) - , defineProperty = __webpack_require__(7).f; -module.exports = function(name){ - var $Symbol = core.Symbol || (core.Symbol = LIBRARY ? {} : global.Symbol || {}); - if(name.charAt(0) != '_' && !(name in $Symbol))defineProperty($Symbol, name, {value: wksExt.f(name)}); -}; - -/***/ }), -/* 86 */ -/***/ (function(module, exports, __webpack_require__) { - -var classof = __webpack_require__(48) - , ITERATOR = __webpack_require__(5)('iterator') - , Iterators = __webpack_require__(44); -module.exports = __webpack_require__(24).getIteratorMethod = function(it){ - if(it != undefined)return it[ITERATOR] - || it['@@iterator'] - || Iterators[classof(it)]; -}; - -/***/ }), -/* 87 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var addToUnscopables = __webpack_require__(42) - , step = __webpack_require__(100) - , Iterators = __webpack_require__(44) - , toIObject = __webpack_require__(15); - -// 22.1.3.4 Array.prototype.entries() -// 22.1.3.13 Array.prototype.keys() -// 22.1.3.29 Array.prototype.values() -// 22.1.3.30 Array.prototype[@@iterator]() -module.exports = __webpack_require__(72)(Array, 'Array', function(iterated, kind){ - this._t = toIObject(iterated); // target - this._i = 0; // next index - this._k = kind; // kind -// 22.1.5.2.1 %ArrayIteratorPrototype%.next() -}, function(){ - var O = this._t - , kind = this._k - , index = this._i++; - if(!O || index >= O.length){ - this._t = undefined; - return step(1); - } - if(kind == 'keys' )return step(0, index); - if(kind == 'values')return step(0, O[index]); - return step(0, [index, O[index]]); -}, 'values'); - -// argumentsList[@@iterator] is %ArrayProto_values% (9.4.4.6, 9.4.4.7) -Iterators.Arguments = Iterators.Array; - -addToUnscopables('keys'); -addToUnscopables('values'); -addToUnscopables('entries'); - -/***/ }), -/* 88 */ -/***/ (function(module, exports) { - -var g; - -// This works in non-strict mode -g = (function() { - return this; -})(); - -try { - // This works if eval is allowed (see CSP) - g = g || Function("return this")() || (1,eval)("this"); -} catch(e) { - // This works if the window reference is available - if(typeof window === "object") - g = window; -} - -// g can still be undefined, but nothing to do about it... -// We return undefined, instead of nothing here, so it's -// easier to handle this case. if(!global) { ...} - -module.exports = g; - - -/***/ }), -/* 89 */ -/***/ (function(module, exports, __webpack_require__) { - -var cof = __webpack_require__(18); -module.exports = function(it, msg){ - if(typeof it != 'number' && cof(it) != 'Number')throw TypeError(msg); - return +it; -}; - -/***/ }), -/* 90 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -// 22.1.3.3 Array.prototype.copyWithin(target, start, end = this.length) - -var toObject = __webpack_require__(9) - , toIndex = __webpack_require__(39) - , toLength = __webpack_require__(8); - -module.exports = [].copyWithin || function copyWithin(target/*= 0*/, start/*= 0, end = @length*/){ - var O = toObject(this) - , len = toLength(O.length) - , to = toIndex(target, len) - , from = toIndex(start, len) - , end = arguments.length > 2 ? arguments[2] : undefined - , count = Math.min((end === undefined ? len : toIndex(end, len)) - from, len - to) - , inc = 1; - if(from < to && to < from + count){ - inc = -1; - from += count - 1; - to += count - 1; - } - while(count-- > 0){ - if(from in O)O[to] = O[from]; - else delete O[to]; - to += inc; - from += inc; - } return O; -}; - -/***/ }), -/* 91 */ -/***/ (function(module, exports, __webpack_require__) { - -var forOf = __webpack_require__(43); - -module.exports = function(iter, ITERATOR){ - var result = []; - forOf(iter, false, result.push, result, ITERATOR); - return result; -}; - - -/***/ }), -/* 92 */ -/***/ (function(module, exports, __webpack_require__) { - -var aFunction = __webpack_require__(11) - , toObject = __webpack_require__(9) - , IObject = __webpack_require__(49) - , toLength = __webpack_require__(8); - -module.exports = function(that, callbackfn, aLen, memo, isRight){ - aFunction(callbackfn); - var O = toObject(that) - , self = IObject(O) - , length = toLength(O.length) - , index = isRight ? length - 1 : 0 - , i = isRight ? -1 : 1; - if(aLen < 2)for(;;){ - if(index in self){ - memo = self[index]; - index += i; - break; - } - index += i; - if(isRight ? index < 0 : length <= index){ - throw TypeError('Reduce of empty array with no initial value'); - } - } - for(;isRight ? index >= 0 : length > index; index += i)if(index in self){ - memo = callbackfn(memo, self[index], index, O); - } - return memo; -}; - -/***/ }), -/* 93 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var aFunction = __webpack_require__(11) - , isObject = __webpack_require__(4) - , invoke = __webpack_require__(55) - , arraySlice = [].slice - , factories = {}; - -var construct = function(F, len, args){ - if(!(len in factories)){ - for(var n = [], i = 0; i < len; i++)n[i] = 'a[' + i + ']'; - factories[len] = Function('F,a', 'return new F(' + n.join(',') + ')'); - } return factories[len](F, args); -}; - -module.exports = Function.bind || function bind(that /*, args... */){ - var fn = aFunction(this) - , partArgs = arraySlice.call(arguments, 1); - var bound = function(/* args... */){ - var args = partArgs.concat(arraySlice.call(arguments)); - return this instanceof bound ? construct(fn, args.length, args) : invoke(fn, args, that); - }; - if(isObject(fn.prototype))bound.prototype = fn.prototype; - return bound; -}; - -/***/ }), -/* 94 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var dP = __webpack_require__(7).f - , create = __webpack_require__(34) - , redefineAll = __webpack_require__(37) - , ctx = __webpack_require__(25) - , anInstance = __webpack_require__(32) - , defined = __webpack_require__(19) - , forOf = __webpack_require__(43) - , $iterDefine = __webpack_require__(72) - , step = __webpack_require__(100) - , setSpecies = __webpack_require__(38) - , DESCRIPTORS = __webpack_require__(6) - , fastKey = __webpack_require__(29).fastKey - , SIZE = DESCRIPTORS ? '_s' : 'size'; - -var getEntry = function(that, key){ - // fast case - var index = fastKey(key), entry; - if(index !== 'F')return that._i[index]; - // frozen object case - for(entry = that._f; entry; entry = entry.n){ - if(entry.k == key)return entry; - } -}; - -module.exports = { - getConstructor: function(wrapper, NAME, IS_MAP, ADDER){ - var C = wrapper(function(that, iterable){ - anInstance(that, C, NAME, '_i'); - that._i = create(null); // index - that._f = undefined; // first entry - that._l = undefined; // last entry - that[SIZE] = 0; // size - if(iterable != undefined)forOf(iterable, IS_MAP, that[ADDER], that); - }); - redefineAll(C.prototype, { - // 23.1.3.1 Map.prototype.clear() - // 23.2.3.2 Set.prototype.clear() - clear: function clear(){ - for(var that = this, data = that._i, entry = that._f; entry; entry = entry.n){ - entry.r = true; - if(entry.p)entry.p = entry.p.n = undefined; - delete data[entry.i]; - } - that._f = that._l = undefined; - that[SIZE] = 0; - }, - // 23.1.3.3 Map.prototype.delete(key) - // 23.2.3.4 Set.prototype.delete(value) - 'delete': function(key){ - var that = this - , entry = getEntry(that, key); - if(entry){ - var next = entry.n - , prev = entry.p; - delete that._i[entry.i]; - entry.r = true; - if(prev)prev.n = next; - if(next)next.p = prev; - if(that._f == entry)that._f = next; - if(that._l == entry)that._l = prev; - that[SIZE]--; - } return !!entry; - }, - // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined) - // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined) - forEach: function forEach(callbackfn /*, that = undefined */){ - anInstance(this, C, 'forEach'); - var f = ctx(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3) - , entry; - while(entry = entry ? entry.n : this._f){ - f(entry.v, entry.k, this); - // revert to the last existing entry - while(entry && entry.r)entry = entry.p; - } - }, - // 23.1.3.7 Map.prototype.has(key) - // 23.2.3.7 Set.prototype.has(value) - has: function has(key){ - return !!getEntry(this, key); - } - }); - if(DESCRIPTORS)dP(C.prototype, 'size', { - get: function(){ - return defined(this[SIZE]); - } - }); - return C; - }, - def: function(that, key, value){ - var entry = getEntry(that, key) - , prev, index; - // change existing entry - if(entry){ - entry.v = value; - // create new entry - } else { - that._l = entry = { - i: index = fastKey(key, true), // <- index - k: key, // <- key - v: value, // <- value - p: prev = that._l, // <- previous entry - n: undefined, // <- next entry - r: false // <- removed - }; - if(!that._f)that._f = entry; - if(prev)prev.n = entry; - that[SIZE]++; - // add to index - if(index !== 'F')that._i[index] = entry; - } return that; - }, - getEntry: getEntry, - setStrong: function(C, NAME, IS_MAP){ - // add .keys, .values, .entries, [@@iterator] - // 23.1.3.4, 23.1.3.8, 23.1.3.11, 23.1.3.12, 23.2.3.5, 23.2.3.8, 23.2.3.10, 23.2.3.11 - $iterDefine(C, NAME, function(iterated, kind){ - this._t = iterated; // target - this._k = kind; // kind - this._l = undefined; // previous - }, function(){ - var that = this - , kind = that._k - , entry = that._l; - // revert to the last existing entry - while(entry && entry.r)entry = entry.p; - // get next entry - if(!that._t || !(that._l = entry = entry ? entry.n : that._t._f)){ - // or finish the iteration - that._t = undefined; - return step(1); - } - // return step by kind - if(kind == 'keys' )return step(0, entry.k); - if(kind == 'values')return step(0, entry.v); - return step(0, [entry.k, entry.v]); - }, IS_MAP ? 'entries' : 'values' , !IS_MAP, true); - - // add [@@species], 23.1.2.2, 23.2.2.2 - setSpecies(NAME); - } -}; - -/***/ }), -/* 95 */ -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var classof = __webpack_require__(48) - , from = __webpack_require__(91); -module.exports = function(NAME){ - return function toJSON(){ - if(classof(this) != NAME)throw TypeError(NAME + "#toJSON isn't generic"); - return from(this); - }; -}; - -/***/ }), -/* 96 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var redefineAll = __webpack_require__(37) - , getWeak = __webpack_require__(29).getWeak - , anObject = __webpack_require__(1) - , isObject = __webpack_require__(4) - , anInstance = __webpack_require__(32) - , forOf = __webpack_require__(43) - , createArrayMethod = __webpack_require__(21) - , $has = __webpack_require__(10) - , arrayFind = createArrayMethod(5) - , arrayFindIndex = createArrayMethod(6) - , id = 0; - -// fallback for uncaught frozen keys -var uncaughtFrozenStore = function(that){ - return that._l || (that._l = new UncaughtFrozenStore); -}; -var UncaughtFrozenStore = function(){ - this.a = []; -}; -var findUncaughtFrozen = function(store, key){ - return arrayFind(store.a, function(it){ - return it[0] === key; - }); -}; -UncaughtFrozenStore.prototype = { - get: function(key){ - var entry = findUncaughtFrozen(this, key); - if(entry)return entry[1]; - }, - has: function(key){ - return !!findUncaughtFrozen(this, key); - }, - set: function(key, value){ - var entry = findUncaughtFrozen(this, key); - if(entry)entry[1] = value; - else this.a.push([key, value]); - }, - 'delete': function(key){ - var index = arrayFindIndex(this.a, function(it){ - return it[0] === key; - }); - if(~index)this.a.splice(index, 1); - return !!~index; - } -}; - -module.exports = { - getConstructor: function(wrapper, NAME, IS_MAP, ADDER){ - var C = wrapper(function(that, iterable){ - anInstance(that, C, NAME, '_i'); - that._i = id++; // collection id - that._l = undefined; // leak store for uncaught frozen objects - if(iterable != undefined)forOf(iterable, IS_MAP, that[ADDER], that); - }); - redefineAll(C.prototype, { - // 23.3.3.2 WeakMap.prototype.delete(key) - // 23.4.3.3 WeakSet.prototype.delete(value) - 'delete': function(key){ - if(!isObject(key))return false; - var data = getWeak(key); - if(data === true)return uncaughtFrozenStore(this)['delete'](key); - return data && $has(data, this._i) && delete data[this._i]; - }, - // 23.3.3.4 WeakMap.prototype.has(key) - // 23.4.3.4 WeakSet.prototype.has(value) - has: function has(key){ - if(!isObject(key))return false; - var data = getWeak(key); - if(data === true)return uncaughtFrozenStore(this).has(key); - return data && $has(data, this._i); - } - }); - return C; - }, - def: function(that, key, value){ - var data = getWeak(anObject(key), true); - if(data === true)uncaughtFrozenStore(that).set(key, value); - else data[that._i] = value; - return that; - }, - ufstore: uncaughtFrozenStore -}; - -/***/ }), -/* 97 */ -/***/ (function(module, exports, __webpack_require__) { - -module.exports = !__webpack_require__(6) && !__webpack_require__(3)(function(){ - return Object.defineProperty(__webpack_require__(64)('div'), 'a', {get: function(){ return 7; }}).a != 7; -}); - -/***/ }), -/* 98 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.1.2.3 Number.isInteger(number) -var isObject = __webpack_require__(4) - , floor = Math.floor; -module.exports = function isInteger(it){ - return !isObject(it) && isFinite(it) && floor(it) === it; -}; - -/***/ }), -/* 99 */ -/***/ (function(module, exports, __webpack_require__) { - -// call something on iterator step with safe closing on error -var anObject = __webpack_require__(1); -module.exports = function(iterator, fn, value, entries){ - try { - return entries ? fn(anObject(value)[0], value[1]) : fn(value); - // 7.4.6 IteratorClose(iterator, completion) - } catch(e){ - var ret = iterator['return']; - if(ret !== undefined)anObject(ret.call(iterator)); - throw e; - } -}; - -/***/ }), -/* 100 */ -/***/ (function(module, exports) { - -module.exports = function(done, value){ - return {value: value, done: !!done}; -}; - -/***/ }), -/* 101 */ -/***/ (function(module, exports) { - -// 20.2.2.20 Math.log1p(x) -module.exports = Math.log1p || function log1p(x){ - return (x = +x) > -1e-8 && x < 1e-8 ? x - x * x / 2 : Math.log(1 + x); -}; - -/***/ }), -/* 102 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// 19.1.2.1 Object.assign(target, source, ...) -var getKeys = __webpack_require__(36) - , gOPS = __webpack_require__(59) - , pIE = __webpack_require__(50) - , toObject = __webpack_require__(9) - , IObject = __webpack_require__(49) - , $assign = Object.assign; - -// should work with symbols and should have deterministic property order (V8 bug) -module.exports = !$assign || __webpack_require__(3)(function(){ - var A = {} - , B = {} - , S = Symbol() - , K = 'abcdefghijklmnopqrst'; - A[S] = 7; - K.split('').forEach(function(k){ B[k] = k; }); - return $assign({}, A)[S] != 7 || Object.keys($assign({}, B)).join('') != K; -}) ? function assign(target, source){ // eslint-disable-line no-unused-vars - var T = toObject(target) - , aLen = arguments.length - , index = 1 - , getSymbols = gOPS.f - , isEnum = pIE.f; - while(aLen > index){ - var S = IObject(arguments[index++]) - , keys = getSymbols ? getKeys(S).concat(getSymbols(S)) : getKeys(S) - , length = keys.length - , j = 0 - , key; - while(length > j)if(isEnum.call(S, key = keys[j++]))T[key] = S[key]; - } return T; -} : $assign; - -/***/ }), -/* 103 */ -/***/ (function(module, exports, __webpack_require__) { - -var dP = __webpack_require__(7) - , anObject = __webpack_require__(1) - , getKeys = __webpack_require__(36); - -module.exports = __webpack_require__(6) ? Object.defineProperties : function defineProperties(O, Properties){ - anObject(O); - var keys = getKeys(Properties) - , length = keys.length - , i = 0 - , P; - while(length > i)dP.f(O, P = keys[i++], Properties[P]); - return O; -}; - -/***/ }), -/* 104 */ -/***/ (function(module, exports, __webpack_require__) { - -// fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window -var toIObject = __webpack_require__(15) - , gOPN = __webpack_require__(35).f - , toString = {}.toString; - -var windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames - ? Object.getOwnPropertyNames(window) : []; - -var getWindowNames = function(it){ - try { - return gOPN(it); - } catch(e){ - return windowNames.slice(); - } -}; - -module.exports.f = function getOwnPropertyNames(it){ - return windowNames && toString.call(it) == '[object Window]' ? getWindowNames(it) : gOPN(toIObject(it)); -}; - - -/***/ }), -/* 105 */ -/***/ (function(module, exports, __webpack_require__) { - -var has = __webpack_require__(10) - , toIObject = __webpack_require__(15) - , arrayIndexOf = __webpack_require__(51)(false) - , IE_PROTO = __webpack_require__(77)('IE_PROTO'); - -module.exports = function(object, names){ - var O = toIObject(object) - , i = 0 - , result = [] - , key; - for(key in O)if(key != IE_PROTO)has(O, key) && result.push(key); - // Don't enum bug & hidden keys - while(names.length > i)if(has(O, key = names[i++])){ - ~arrayIndexOf(result, key) || result.push(key); - } - return result; -}; - -/***/ }), -/* 106 */ -/***/ (function(module, exports, __webpack_require__) { - -var getKeys = __webpack_require__(36) - , toIObject = __webpack_require__(15) - , isEnum = __webpack_require__(50).f; -module.exports = function(isEntries){ - return function(it){ - var O = toIObject(it) - , keys = getKeys(O) - , length = keys.length - , i = 0 - , result = [] - , key; - while(length > i)if(isEnum.call(O, key = keys[i++])){ - result.push(isEntries ? [key, O[key]] : O[key]); - } return result; - }; -}; - -/***/ }), -/* 107 */ -/***/ (function(module, exports, __webpack_require__) { - -// all object keys, includes non-enumerable and symbols -var gOPN = __webpack_require__(35) - , gOPS = __webpack_require__(59) - , anObject = __webpack_require__(1) - , Reflect = __webpack_require__(2).Reflect; -module.exports = Reflect && Reflect.ownKeys || function ownKeys(it){ - var keys = gOPN.f(anObject(it)) - , getSymbols = gOPS.f; - return getSymbols ? keys.concat(getSymbols(it)) : keys; -}; - -/***/ }), -/* 108 */ -/***/ (function(module, exports, __webpack_require__) { - -var $parseFloat = __webpack_require__(2).parseFloat - , $trim = __webpack_require__(46).trim; - -module.exports = 1 / $parseFloat(__webpack_require__(82) + '-0') !== -Infinity ? function parseFloat(str){ - var string = $trim(String(str), 3) - , result = $parseFloat(string); - return result === 0 && string.charAt(0) == '-' ? -0 : result; -} : $parseFloat; - -/***/ }), -/* 109 */ -/***/ (function(module, exports, __webpack_require__) { - -var $parseInt = __webpack_require__(2).parseInt - , $trim = __webpack_require__(46).trim - , ws = __webpack_require__(82) - , hex = /^[\-+]?0[xX]/; - -module.exports = $parseInt(ws + '08') !== 8 || $parseInt(ws + '0x16') !== 22 ? function parseInt(str, radix){ - var string = $trim(String(str), 3); - return $parseInt(string, (radix >>> 0) || (hex.test(string) ? 16 : 10)); -} : $parseInt; - -/***/ }), -/* 110 */ -/***/ (function(module, exports) { - -// 7.2.9 SameValue(x, y) -module.exports = Object.is || function is(x, y){ - return x === y ? x !== 0 || 1 / x === 1 / y : x != x && y != y; -}; - -/***/ }), -/* 111 */ -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/tc39/proposal-string-pad-start-end -var toLength = __webpack_require__(8) - , repeat = __webpack_require__(81) - , defined = __webpack_require__(19); - -module.exports = function(that, maxLength, fillString, left){ - var S = String(defined(that)) - , stringLength = S.length - , fillStr = fillString === undefined ? ' ' : String(fillString) - , intMaxLength = toLength(maxLength); - if(intMaxLength <= stringLength || fillStr == '')return S; - var fillLen = intMaxLength - stringLength - , stringFiller = repeat.call(fillStr, Math.ceil(fillLen / fillStr.length)); - if(stringFiller.length > fillLen)stringFiller = stringFiller.slice(0, fillLen); - return left ? stringFiller + S : S + stringFiller; -}; - - -/***/ }), -/* 112 */ -/***/ (function(module, exports, __webpack_require__) { - -exports.f = __webpack_require__(5); - -/***/ }), -/* 113 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__(94); - -// 23.1 Map Objects -module.exports = __webpack_require__(52)('Map', function(get){ - return function Map(){ return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.1.3.6 Map.prototype.get(key) - get: function get(key){ - var entry = strong.getEntry(this, key); - return entry && entry.v; - }, - // 23.1.3.9 Map.prototype.set(key, value) - set: function set(key, value){ - return strong.def(this, key === 0 ? 0 : key, value); - } -}, strong, true); - -/***/ }), -/* 114 */ -/***/ (function(module, exports, __webpack_require__) { - -// 21.2.5.3 get RegExp.prototype.flags() -if(__webpack_require__(6) && /./g.flags != 'g')__webpack_require__(7).f(RegExp.prototype, 'flags', { - configurable: true, - get: __webpack_require__(54) -}); - -/***/ }), -/* 115 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__(94); - -// 23.2 Set Objects -module.exports = __webpack_require__(52)('Set', function(get){ - return function Set(){ return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value){ - return strong.def(this, value = value === 0 ? 0 : value, value); - } -}, strong); - -/***/ }), -/* 116 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var each = __webpack_require__(21)(0) - , redefine = __webpack_require__(13) - , meta = __webpack_require__(29) - , assign = __webpack_require__(102) - , weak = __webpack_require__(96) - , isObject = __webpack_require__(4) - , getWeak = meta.getWeak - , isExtensible = Object.isExtensible - , uncaughtFrozenStore = weak.ufstore - , tmp = {} - , InternalMap; - -var wrapper = function(get){ - return function WeakMap(){ - return get(this, arguments.length > 0 ? arguments[0] : undefined); - }; -}; - -var methods = { - // 23.3.3.3 WeakMap.prototype.get(key) - get: function get(key){ - if(isObject(key)){ - var data = getWeak(key); - if(data === true)return uncaughtFrozenStore(this).get(key); - return data ? data[this._i] : undefined; - } - }, - // 23.3.3.5 WeakMap.prototype.set(key, value) - set: function set(key, value){ - return weak.def(this, key, value); - } -}; - -// 23.3 WeakMap Objects -var $WeakMap = module.exports = __webpack_require__(52)('WeakMap', wrapper, methods, weak, true, true); - -// IE11 WeakMap frozen keys fix -if(new $WeakMap().set((Object.freeze || Object)(tmp), 7).get(tmp) != 7){ - InternalMap = weak.getConstructor(wrapper); - assign(InternalMap.prototype, methods); - meta.NEED = true; - each(['delete', 'has', 'get', 'set'], function(key){ - var proto = $WeakMap.prototype - , method = proto[key]; - redefine(proto, key, function(a, b){ - // store frozen objects on internal weakmap shim - if(isObject(a) && !isExtensible(a)){ - if(!this._f)this._f = new InternalMap; - var result = this._f[key](a, b); - return key == 'set' ? this : result; - // store all the rest on native weakmap - } return method.call(this, a, b); - }); - }); -} - -/***/ }), -/* 117 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _widgetBtn = __webpack_require__(123); - -var _widgetBtn2 = _interopRequireDefault(_widgetBtn); - -var _listBoard = __webpack_require__(120); - -var _listBoard2 = _interopRequireDefault(_listBoard); - -var _chatSection = __webpack_require__(119); - -var _chatSection2 = _interopRequireDefault(_chatSection); - -var _popup = __webpack_require__(121); - -var _popup2 = _interopRequireDefault(_popup); - -var _spinner2 = __webpack_require__(122); - -var _spinner3 = _interopRequireDefault(_spinner2); - -var _sendbird = __webpack_require__(124); - -var _sendbird2 = _interopRequireDefault(_sendbird); - -var _utils = __webpack_require__(41); - -var _consts = __webpack_require__(28); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var WIDGET_ID = 'sb_widget'; -var TIME_STRING_TODAY = 'TODAY'; -var TIME_MESSAGE_TYPE = 'time'; -var NEW_CHAT_BOARD_ID = 'NEW_CHAT'; -var KEY_DOWN_ENTER = 13; -var KEY_DOWN_KR = 229; -var CHAT_BOARD_WIDTH = 300; -var ERROR_MESSAGE = 'Please create "sb_widget" element on first.'; -var ERROR_MESSAGE_SDK = 'Please import "SendBird SDK" on first.'; -var EVENT_TYPE_CLICK = 'click'; - -window.WebFontConfig = { - google: { families: ['Lato:400,700'] } -}; - -var SBWidget = function () { - function SBWidget() { - _classCallCheck(this, SBWidget); - } - - _createClass(SBWidget, [{ - key: 'start', - value: function start(appId) { - var _this = this; - - if (!window.SendBird) { - console.error(ERROR_MESSAGE_SDK); - return; - } - this._getGoogleFont(); - this.widget = document.getElementById(WIDGET_ID); - if (this.widget) { - document.addEventListener(EVENT_TYPE_CLICK, function (event) { - _this._initClickEvent(event); - }); - this._init(); - this._start(appId); - } else { - console.error(ERROR_MESSAGE); - } - } - }, { - key: 'startWithConnect', - value: function startWithConnect(appId, userId, nickname, callback) { - var _this2 = this; - - if (!window.SendBird) { - console.error(ERROR_MESSAGE_SDK); - return; - } - this._getGoogleFont(); - this.widget = document.getElementById(WIDGET_ID); - if (this.widget) { - document.addEventListener(EVENT_TYPE_CLICK, function (event) { - _this2._initClickEvent(event); - }); - this._init(); - this._start(appId); - this._connect(userId, nickname, callback); - } else { - console.error(ERROR_MESSAGE); - } - } - }, { - key: '_initClickEvent', - value: function _initClickEvent(event) { - var _checkPopup = function _checkPopup(_target, obj) { - if (obj === _target || (0, _utils.hasClass)(_target, _consts.className.IC_MEMBERS) || (0, _utils.hasClass)(_target, _consts.className.IC_INVITE)) { - return true; - } else { - var returnedCheck = false; - for (var i = 0; i < obj.childNodes.length; i++) { - returnedCheck = _checkPopup(_target, obj.childNodes[i]); - if (returnedCheck) break; - } - return returnedCheck; - } - }; - - if (!_checkPopup(event.target, this.popup.memberPopup)) { - this.closeMemberPopup(); - } - if (!_checkPopup(event.target, this.popup.invitePopup)) { - this.closeInvitePopup(); - } - } - }, { - key: '_init', - value: function _init() { - this.spinner = new _spinner3.default(); - - this.widgetBtn = new _widgetBtn2.default(this.widget); - this.listBoard = new _listBoard2.default(this.widget); - this.chatSection = new _chatSection2.default(this.widget); - this.popup = new _popup2.default(); - - this.activeChannelSetList = []; - this.extraChannelSetList = []; - - this.timeMessage = function () { - function TimeMessage(date) { - _classCallCheck(this, TimeMessage); - - this.time = date; - this.type = TIME_MESSAGE_TYPE; - } - - _createClass(TimeMessage, [{ - key: 'isTimeMessage', - value: function isTimeMessage() { - return this.type == TIME_MESSAGE_TYPE; - } - }]); - - return TimeMessage; - }(); - } - }, { - key: '_getGoogleFont', - value: function _getGoogleFont() { - var wf = document.createElement('script'); - wf.src = ('https:' == document.location.protocol ? 'https' : 'http') + '://ajax.googleapis.com/ajax/libs/webfont/1.5.18/webfont.js'; - wf.type = 'text/javascript'; - wf.async = 'true'; - var s = document.getElementsByTagName('script')[0]; - s.parentNode.insertBefore(wf, s); - } - }, { - key: 'reset', - value: function reset() { - this.extraChannelSetList = []; - for (var i = 0; i < this.activeChannelSetList.length; i++) { - var channelSet = this.activeChannelSetList[i]; - var targetBoard = this.chatSection.getChatBoard(channelSet.channel.url); - if (targetBoard) { - this.chatSection.closeChatBoard(targetBoard); - } - } - this.activeChannelSetList = []; - this.closePopup(); - - this.sb.reset(); - this.listBoard.reset(); - this.widgetBtn.reset(); - } - }, { - key: 'responsiveChatSection', - value: function responsiveChatSection(channelUrl, isShow) { - var _bodyWidth = document.getElementsByTagName('BODY')[0].offsetWidth - 360; - var maxSize = parseInt(_bodyWidth / CHAT_BOARD_WIDTH); - var currentSize = this.activeChannelSetList.length; - if (currentSize >= maxSize) { - var extraChannelSet = (0, _utils.getLastItem)(this.activeChannelSetList); - if (extraChannelSet) { - if (this.extraChannelSetList.indexOf(extraChannelSet.channel.url) < 0) { - this.extraChannelSetList.push(extraChannelSet.channel.url); - } - var chatBoard = this.chatSection.getChatBoard(extraChannelSet.channel.url); - if (chatBoard) { - this.chatSection.closeChatBoard(chatBoard); - } - this.removeChannelSet(extraChannelSet.channel); - } - if (channelUrl) { - var idx = this.extraChannelSetList.indexOf(channelUrl); - if (idx > -1) { - this.extraChannelSetList.splice(idx, 1); - } - } - this.chatSection.setWidth(maxSize * CHAT_BOARD_WIDTH); - } else { - var popChannelUrl = this.extraChannelSetList.pop(); - if (popChannelUrl) { - this._connectChannel(popChannelUrl, true); - this.chatSection.setWidth((currentSize + 1) * CHAT_BOARD_WIDTH); - } else { - if (isShow) { - currentSize += 1; - } - this.chatSection.setWidth(currentSize * CHAT_BOARD_WIDTH); - } - } - } - }, { - key: '_start', - value: function _start(appId) { - var _this3 = this; - - this.sb = new _sendbird2.default(appId); - - this.popup.addCloseBtnClickEvent(function () { - _this3.closePopup(); - }); - - this.widgetBtn.addClickEvent(function () { - _this3.sb.isConnected() ? _this3.listBoard.showChannelList() : _this3.listBoard.showLoginForm(); - _this3.toggleBoard(true); - _this3.listBoard.addChannelListScrollEvent(function () { - _this3.getChannelList(); - }); - _this3.chatSection.responsiveSize(false, _this3.responsiveChatSection.bind(_this3)); - }); - - this.listBoard.addNewChatClickEvent(function () { - _this3.listBoard.hideLogoutBtn(); - - var chatBoard = _this3.chatSection.createChatBoard(NEW_CHAT_BOARD_ID); - _this3.responsiveChatSection(null, true); - - _this3.chatSection.createNewChatBoard(chatBoard); - _this3.chatSection.addClickEvent(chatBoard.startBtn, function () { - if (!(0, _utils.hasClass)(chatBoard.startBtn, _consts.className.DISABLED)) { - (0, _utils.addClass)(chatBoard.startBtn, _consts.className.DISABLED); - _this3.sb.userListQuery = null; - _this3.spinner.insert(chatBoard.startBtn); - var selectedUserIds = _this3.chatSection.getSelectedUserIds(chatBoard.userContent); - _this3.sb.createNewChannel(selectedUserIds, function (channel) { - chatBoard.parentNode.removeChild(chatBoard); - _this3._connectChannel(channel.url, true); - _this3.listBoard.checkEmptyList(); - }); - } - }); - _this3.spinner.insert(chatBoard.userContent); - - _this3.sb.getUserList(function (userList) { - _this3.spinner.remove(chatBoard.userContent); - _this3.setUserList(chatBoard, userList); - }); - - _this3.chatSection.addClickEvent(chatBoard.closeBtn, function () { - _this3.chatSection.closeChatBoard(chatBoard); - _this3.closePopup(); - _this3.responsiveChatSection(); - }); - (0, _utils.hide)(chatBoard.leaveBtn); - (0, _utils.hide)(chatBoard.memberBtn); - (0, _utils.hide)(chatBoard.inviteBtn); - }); - - this.listBoard.addMinimizeClickEvent(function () { - _this3.listBoard.hideLogoutBtn(); - _this3.closePopup(); - _this3.toggleBoard(false); - _this3.chatSection.responsiveSize(true, _this3.responsiveChatSection.bind(_this3)); - }); - - this.listBoard.addLogoutClickEvent(function () { - _this3.sb.disconnect(function () { - _this3.sb.reset(); - _this3.toggleBoard(false); - _this3.widgetBtn.toggleIcon(false); - _this3.listBoard.setOptionEventLock(false); - _this3.chatSection.reset(); - _this3.reset(); - }); - }); - - this.listBoard.addLoginClickEvent(function () { - if (!(0, _utils.hasClass)(_this3.listBoard.btnLogin, _consts.className.DISABLED)) { - _this3.spinner.insert(_this3.listBoard.btnLogin); - _this3.listBoard.enabledToggle(_this3.listBoard.btnLogin, false); - _this3.listBoard.userId.disabled = true; - _this3.listBoard.nickname.disabled = true; - - _this3._connect(_this3.listBoard.getUserId(), _this3.listBoard.getNickname()); - } - }); - this.listBoard.addKeyDownEvent(this.listBoard.nickname, function (event) { - if (event.keyCode == KEY_DOWN_ENTER) { - _this3.listBoard.btnLogin.click(); - } - }); - } - }, { - key: '_connect', - value: function _connect(userId, nickname, callback) { - var _this4 = this; - - this.sb.connect(userId, nickname, function () { - _this4.widgetBtn.toggleIcon(true); - - _this4.listBoard.showChannelList(); - _this4.spinner.insert(_this4.listBoard.list); - _this4.getChannelList(); - - _this4.sb.createHandlerGlobal(function (channel, message) { - _this4.messageReceivedAction(channel, message); - }, function (channel) { - _this4.updateUnreadMessageCount(channel); - }, function (channel) { - var targetBoard = _this4.chatSection.getChatBoard(channel.url); - if (targetBoard) { - var isBottom = _this4.chatSection.isBottom(targetBoard.messageContent, targetBoard.list); - _this4.chatSection.showTyping(channel, _this4.spinner); - _this4.chatSection.responsiveHeight(channel.url); - if (isBottom) { - _this4.chatSection.scrollToBottom(targetBoard.messageContent); - } - } - }, function (channel) { - var targetBoard = _this4.chatSection.getChatBoard(channel.url); - if (targetBoard) { - var channelSet = _this4.getChannelSet(channel.url); - if (channelSet) { - _this4.chatSection.updateReadReceipt(channelSet, targetBoard); - } - } - }, function (channel, user) { - if (_this4.sb.isCurrentUser(user)) { - var item = _this4.listBoard.getChannelItem(channel.url); - _this4.listBoard.list.removeChild(item); - _this4.listBoard.checkEmptyList(); - } else { - _this4.listBoard.setChannelTitle(channel.url, _this4.sb.getNicknamesString(channel)); - _this4.updateUnreadMessageCount(channel); - var targetChatBoard = _this4.chatSection.getChatBoard(channel.url); - if (targetChatBoard) { - _this4.updateChannelInfo(targetChatBoard, channel); - } - } - }, function (channel, user) { - _this4.listBoard.setChannelTitle(channel.url, _this4.sb.getNicknamesString(channel)); - var targetChatBoard = _this4.chatSection.getChatBoard(channel.url); - if (targetChatBoard) { - _this4.updateChannelInfo(targetChatBoard, channel); - } - }); - - if (callback) callback(); - }); - } - }, { - key: 'messageReceivedAction', - value: function messageReceivedAction(channel, message) { - var target = this.listBoard.getChannelItem(channel.url); - if (!target) { - target = this.createChannelItem(channel); - this.listBoard.checkEmptyList(); - } - this.listBoard.addListOnFirstIndex(target); - - this.listBoard.setChannelLastMessage(channel.url, message.isFileMessage() ? message.name : message.message); - this.listBoard.setChannelLastMessageTime(channel.url, this.sb.getMessageTime(message)); - - var targetBoard = this.chatSection.getChatBoard(channel.url); - if (targetBoard) { - var isBottom = this.chatSection.isBottom(targetBoard.messageContent, targetBoard.list); - var channelSet = this.getChannelSet(channel.url); - var lastMessage = (0, _utils.getLastItem)(channelSet.message); - channelSet.message.push(message); - this.setMessageItem(channelSet.channel, targetBoard, [message], false, isBottom, lastMessage); - channel.markAsRead(); - this.updateUnreadMessageCount(channel); - } - } - }, { - key: 'setUserList', - value: function setUserList(target, userList) { - var _this5 = this; - - var userContent = target.userContent; - this.chatSection.createUserList(userContent); - for (var i = 0; i < userList.length; i++) { - var user = userList[i]; - if (!this.sb.isCurrentUser(user)) { - (function () { - var item = _this5.chatSection.createUserListItem(user); - _this5.chatSection.addClickEvent(item, function () { - (0, _utils.hasClass)(item.select, _consts.className.ACTIVE) ? (0, _utils.removeClass)(item.select, _consts.className.ACTIVE) : (0, _utils.addClass)(item.select, _consts.className.ACTIVE); - var selectedUserCount = _this5.chatSection.getSelectedUserIds(userContent.list).length; - _this5.chatSection.updateChatTop(target, selectedUserCount > 9 ? _consts.MAX_COUNT : selectedUserCount.toString(), null); - selectedUserCount > 0 ? (0, _utils.removeClass)(target.startBtn, _consts.className.DISABLED) : (0, _utils.addClass)(target.startBtn, _consts.className.DISABLED); - }); - userContent.list.appendChild(item); - })(); - } - } - this.chatSection.addUserListScrollEvent(target, function () { - _this5.sb.getUserList(function (userList) { - _this5.setUserList(target, userList); - }); - }); - } - }, { - key: 'getChannelList', - value: function getChannelList() { - var _this6 = this; - - var _list = this.listBoard.list; - var _spinner = this.spinner; - this.sb.getChannelList(function (channelList) { - if (_list.lastElementChild == _spinner.self) { - _spinner.remove(_list); - } - channelList.forEach(function (channel) { - var item = _this6.createChannelItem(channel); - _list.appendChild(item); - }); - _this6.updateUnreadMessageCount(); - _this6.listBoard.checkEmptyList(); - }); - } - }, { - key: 'createChannelItem', - value: function createChannelItem(channel) { - var _this7 = this; - - var item = this.listBoard.createChannelItem(channel.url, channel.coverUrl, this.sb.getNicknamesString(channel), this.sb.getMessageTime(channel.lastMessage), this.sb.getLastMessage(channel), this.sb.getChannelUnreadCount(channel)); - this.listBoard.addChannelClickEvent(item, function () { - _this7.closePopup(); - var channelUrl = item.getAttribute('data-channel-url'); - var openChatBoard = _this7.chatSection.getChatBoard(channelUrl); - if (!openChatBoard) { - var newChat = _this7.chatSection.getChatBoard(NEW_CHAT_BOARD_ID); - if (newChat) { - _this7.chatSection.closeChatBoard(newChat); - } - _this7._connectChannel(channelUrl); - } - }); - return item; - } - }, { - key: 'closePopup', - value: function closePopup() { - this.closeMemberPopup(); - this.closeInvitePopup(); - } - }, { - key: 'closeMemberPopup', - value: function closeMemberPopup() { - this.chatSection.removeMemberPopup(); - this.popup.closeMemberPopup(); - } - }, { - key: 'closeInvitePopup', - value: function closeInvitePopup() { - this.chatSection.removeInvitePopup(); - this.popup.closeInvitePopup(); - this.sb.userListQuery = null; - } - }, { - key: 'showChannel', - value: function showChannel(channelUrl) { - this._connectChannel(channelUrl, false); - } - }, { - key: '_connectChannel', - value: function _connectChannel(channelUrl, doNotCall) { - var _this8 = this; - - var chatBoard = this.chatSection.createChatBoard(channelUrl, doNotCall); - if (!doNotCall) { - this.responsiveChatSection(channelUrl, true); - } - this.chatSection.addClickEvent(chatBoard.closeBtn, function () { - _this8.chatSection.closeChatBoard(chatBoard); - _this8.closePopup(); - _this8.removeChannelSet(channelUrl); - _this8.responsiveChatSection(); - }); - this.chatSection.addClickEvent(chatBoard.leaveBtn, function () { - _this8.chatSection.addLeavePopup(chatBoard); - _this8.chatSection.setLeaveBtnClickEvent(chatBoard.leavePopup.leaveBtn, function () { - _this8.spinner.insert(chatBoard.leavePopup.leaveBtn); - (0, _utils.addClass)(chatBoard.leavePopup.leaveBtn, _consts.className.DISABLED); - var channelSet = _this8.getChannelSet(channelUrl); - if (channelSet) { - _this8.sb.channelLeave(channelSet.channel, function () { - chatBoard.removeChild(chatBoard.leavePopup); - (0, _utils.removeClass)(chatBoard.leavePopup.leaveBtn, _consts.className.DISABLED); - chatBoard.leavePopup = null; - chatBoard.closeBtn.click(); - }); - } else { - _this8.chatSection.closeChatBoard(chatBoard); - } - }); - }); - this.chatSection.addClickEvent(chatBoard.memberBtn, function () { - if ((0, _utils.hasClass)(chatBoard.memberBtn, _consts.className.ACTIVE)) { - _this8.closeMemberPopup(); - } else { - _this8.closeMemberPopup(); - _this8.closeInvitePopup(); - (0, _utils.addClass)(chatBoard.memberBtn, _consts.className.ACTIVE); - var index = _this8.chatSection.indexOfChatBord(channelUrl); - _this8.popup.showMemberPopup(_this8.chatSection.self, index); - var channelSet = _this8.getChannelSet(channelUrl); - _this8.popup.updateCount(_this8.popup.memberPopup.count, channelSet.channel.memberCount); - for (var i = 0; i < channelSet.channel.members.length; i++) { - var member = channelSet.channel.members[i]; - var item = _this8.popup.createMemberItem(member, false, _this8.sb.isCurrentUser(member)); - _this8.popup.memberPopup.list.appendChild(item); - } - } - }); - this.chatSection.addClickEvent(chatBoard.inviteBtn, function () { - var _getUserList = function _getUserList(memberIds, loadmore) { - _this8.sb.getUserList(function (userList) { - if (!loadmore) { - _this8.spinner.remove(_this8.popup.invitePopup.list); - } - for (var i = 0; i < userList.length; i++) { - var user = userList[i]; - if (memberIds.indexOf(user.userId) < 0) { - (function () { - var item = _this8.popup.createMemberItem(user, true); - _this8.popup.addClickEvent(item, function () { - (0, _utils.hasClass)(item.select, _consts.className.ACTIVE) ? (0, _utils.removeClass)(item.select, _consts.className.ACTIVE) : (0, _utils.addClass)(item.select, _consts.className.ACTIVE); - var selectedUserCount = _this8.popup.getSelectedUserIds(_this8.popup.invitePopup.list).length; - _this8.popup.updateCount(_this8.popup.invitePopup.count, selectedUserCount); - selectedUserCount > 0 ? (0, _utils.removeClass)(_this8.popup.invitePopup.inviteBtn, _consts.className.DISABLED) : (0, _utils.addClass)(_this8.popup.invitePopup.inviteBtn, _consts.className.DISABLED); - }); - _this8.popup.invitePopup.list.appendChild(item); - })(); - } - } - }); - }; - - if ((0, _utils.hasClass)(chatBoard.inviteBtn, _consts.className.ACTIVE)) { - _this8.closeInvitePopup(); - } else { - _this8.closeInvitePopup(); - _this8.closeMemberPopup(); - (0, _utils.addClass)(chatBoard.inviteBtn, _consts.className.ACTIVE); - var index = _this8.chatSection.indexOfChatBord(channelUrl); - _this8.popup.showInvitePopup(_this8.chatSection.self, index); - _this8.spinner.insert(_this8.popup.invitePopup.list); - var channelSet = _this8.getChannelSet(channelUrl); - var memberIds = channelSet.channel.members.map(function (member) { - return member.userId; - }); - _getUserList(memberIds); - - _this8.popup.addClickEvent(_this8.popup.invitePopup.inviteBtn, function () { - if (!(0, _utils.hasClass)(_this8.popup.invitePopup.inviteBtn, _consts.className.DISABLED)) { - (0, _utils.addClass)(_this8.popup.invitePopup.inviteBtn, _consts.className.DISABLED); - _this8.spinner.insert(_this8.popup.invitePopup.inviteBtn); - var selectedUserIds = _this8.popup.getSelectedUserIds(_this8.popup.invitePopup.list); - var _channelSet = _this8.getChannelSet(channelUrl); - _this8.sb.inviteMember(_channelSet.channel, selectedUserIds, function () { - _this8.spinner.remove(_this8.popup.invitePopup.inviteBtn); - _this8.closeInvitePopup(); - _this8.listBoard.setChannelTitle(_channelSet.channel.url, _this8.sb.getNicknamesString(_channelSet.channel)); - _this8.updateChannelInfo(chatBoard, _channelSet.channel); - }); - } - }); - - _this8.popup.addScrollEvent(function () { - _getUserList(memberIds, true); - }); - } - }); - this.spinner.insert(chatBoard.content); - this.sb.getChannelInfo(channelUrl, function (channel) { - _this8.updateChannelInfo(chatBoard, channel); - var channelSet = _this8.getChannelSet(channel); - _this8.getMessageList(channelSet, chatBoard, false, function () { - _this8.chatScrollEvent(chatBoard, channelSet); - }); - channel.markAsRead(); - _this8.updateUnreadMessageCount(channel); - - var listItem = _this8.listBoard.getChannelItem(channelUrl); - if (!listItem) { - listItem = _this8.createChannelItem(channel); - _this8.listBoard.list.insertBefore(listItem, _this8.listBoard.list.firstChild); - } - }); - } - }, { - key: 'updateChannelInfo', - value: function updateChannelInfo(target, channel) { - this.chatSection.updateChatTop(target, this.sb.getMemberCount(channel), this.sb.getNicknamesString(channel)); - } - }, { - key: 'updateUnreadMessageCount', - value: function updateUnreadMessageCount(channel) { - var _this9 = this; - - this.sb.getTotalUnreadCount(function (unreadCount) { - _this9.widgetBtn.setUnreadCount(unreadCount); - }); - - if (channel) { - this.listBoard.setChannelUnread(channel.url, channel.unreadMessageCount); - } - } - }, { - key: 'getMessageList', - value: function getMessageList(channelSet, target, loadmore, scrollEvent) { - var _this10 = this; - - this.sb.getMessageList(channelSet, function (messageList) { - var messageItems = messageList.slice(); - var tempTime = void 0; - for (var index = 0; index < messageList.length; index++) { - var message = messageList[index]; - loadmore ? channelSet.message.unshift(message) : channelSet.message.push(message); - - var time = _this10.sb.getMessageTime(message); - if (time.indexOf(':') > -1) { - time = TIME_STRING_TODAY; - } - if (tempTime != time) { - tempTime = time; - (0, _utils.insertMessageInList)(messageItems, messageItems.indexOf(message), new _this10.timeMessage(time)); - } - } - - var scrollToBottom = false; - if (!loadmore) { - if (tempTime != TIME_STRING_TODAY) { - messageItems.push(new _this10.timeMessage(TIME_STRING_TODAY)); - } - scrollToBottom = true; - _this10.spinner.remove(target.content); - _this10.chatSection.createMessageContent(target); - _this10.chatSection.addFileSelectEvent(target.file, function () { - var file = target.file.files[0]; - _this10.sb.sendFileMessage(channelSet.channel, file, function (message) { - _this10.messageReceivedAction(channelSet.channel, message); - }); - }); - _this10.chatSection.addKeyDownEvent(target.input, function (event) { - if (event.keyCode == KEY_DOWN_KR) { - _this10.chatSection.textKr = target.input.textContent; - } - - if (event.keyCode == KEY_DOWN_ENTER && !event.shiftKey) { - var textMessage = target.input.textContent || _this10.chatSection.textKr; - if (!(0, _utils.isEmptyString)(textMessage.trim())) { - _this10.sb.sendTextMessage(channelSet.channel, textMessage, function (message) { - _this10.messageReceivedAction(channelSet.channel, message); - }); - } - _this10.chatSection.clearInputText(target.input, channelSet.channel.url); - _this10.chatSection.textKr = ''; - channelSet.channel.endTyping(); - } else { - channelSet.channel.startTyping(); - } - _this10.chatSection.responsiveHeight(channelSet.channel.url); - }); - _this10.chatSection.addKeyUpEvent(target.input, function (event) { - var isBottom = _this10.chatSection.isBottom(target.messageContent, target.list); - _this10.chatSection.responsiveHeight(channelSet.channel.url); - if (event.keyCode == KEY_DOWN_ENTER && !event.shiftKey) { - _this10.chatSection.clearInputText(target.input, channelSet.channel.url); - if (isBottom) { - _this10.chatSection.scrollToBottom(target.messageContent); - } - } - }); - _this10.chatSection.addPasteEvent(target.input, function (event) { - var clipboardData; - var pastedData; - - event.stopPropagation(); - event.preventDefault(); - - clipboardData = event.clipboardData || window.clipboardData; - pastedData = clipboardData.getData('Text'); - - target.input.textContent += pastedData; - }); - } - if (scrollEvent) { - scrollEvent(); - } - _this10.setMessageItem(channelSet.channel, target, messageItems, loadmore, scrollToBottom); - }); - } - }, { - key: 'setMessageItem', - value: function setMessageItem(channel, target, messageList, loadmore, scrollToBottom, lastMessage) { - var firstChild = target.list.firstChild; - var addScrollHeight = 0; - var prevMessage = void 0; - var newMessage = void 0; - if (lastMessage && messageList[0] && !messageList[0].isTimeMessage) { - prevMessage = lastMessage; - } - for (var i = 0; i < messageList.length; i++) { - var message = messageList[i]; - if (message.isTimeMessage && message.isTimeMessage()) { - newMessage = this.chatSection.createMessageItemTime(message.time); - prevMessage = null; - } else { - var isContinue = false; - if (message.isAdminMessage()) { - newMessage = this.chatSection.createAdminMessageItem(message); - } else { - // isUserMessage() || isFileMessage() - isContinue = prevMessage && prevMessage.sender ? message.sender.userId == prevMessage.sender.userId : false; - var isCurrentUser = this.sb.isCurrentUser(message.sender); - var unreadCount = channel.getReadReceipt(message); - if (message.isUserMessage()) { - newMessage = this.chatSection.createMessageItem(message, isCurrentUser, isContinue, unreadCount); - } else if (message.isFileMessage()) { - newMessage = this.chatSection.createMessageItem(message, isCurrentUser, isContinue, unreadCount); - } - } - prevMessage = message; - } - - if (loadmore) { - target.list.insertBefore(newMessage, firstChild); - addScrollHeight += (0, _utils.getFullHeight)(newMessage); - } else { - target.list.appendChild(newMessage); - } - } - - if (loadmore) { - target.messageContent.scrollTop = addScrollHeight; - } else if (scrollToBottom) { - this.chatSection.scrollToBottom(target.messageContent); - } - } - }, { - key: 'chatScrollEvent', - value: function chatScrollEvent(target, channelSet) { - var _this11 = this; - - this.chatSection.addScrollEvent(target.messageContent, function () { - if (target.messageContent.scrollTop == 0) { - _this11.getMessageList(channelSet, target, true); - } - }); - } - }, { - key: 'getChannelSet', - value: function getChannelSet(channel, isLast) { - var isObject = true; - if ((typeof channel === 'undefined' ? 'undefined' : _typeof(channel)) === _consts.TYPE_STRING || channel instanceof String) { - isObject = false; - } - - var channelSet = this.activeChannelSetList.filter(function (obj) { - return isObject ? obj.channel == channel : obj.channel.url == channel; - })[0]; - - if (!channelSet && isObject) { - channelSet = { - 'channel': channel, - 'query': channel.createPreviousMessageListQuery(), - 'message': [] - }; - isLast ? this.activeChannelSetList.push(channelSet) : this.activeChannelSetList.unshift(channelSet); - } - - return channelSet; - } - }, { - key: 'removeChannelSet', - value: function removeChannelSet(channel) { - var isObject = true; - if ((typeof channel === 'undefined' ? 'undefined' : _typeof(channel)) === _consts.TYPE_STRING || channel instanceof String) { - isObject = false; - } - - this.activeChannelSetList = this.activeChannelSetList.filter(function (obj) { - return isObject ? obj.channel != channel : obj.channel.url != channel; - }); - } - }, { - key: 'toggleBoard', - value: function toggleBoard(isShow) { - if (isShow) { - (0, _utils.hide)((0, _utils.addClass)((0, _utils.removeClass)(this.widgetBtn.self, _consts.className.FADE_IN), _consts.className.FADE_OUT)); - (0, _utils.show)((0, _utils.addClass)((0, _utils.removeClass)(this.listBoard.self, _consts.className.FADE_OUT), _consts.className.FADE_IN)); - } else { - (0, _utils.hide)((0, _utils.addClass)((0, _utils.removeClass)(this.listBoard.self, _consts.className.FADE_IN), _consts.className.FADE_OUT)); - (0, _utils.show)((0, _utils.addClass)((0, _utils.removeClass)(this.widgetBtn.self, _consts.className.FADE_OUT), _consts.className.FADE_IN)); - } - } - }]); - - return SBWidget; -}(); - -window.sbWidget = new SBWidget(); - -/***/ }), -/* 118 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) { - -__webpack_require__(307); - -__webpack_require__(312); - -__webpack_require__(127); - -if (global._babelPolyfill) { - throw new Error("only one instance of babel-polyfill is allowed"); -} -global._babelPolyfill = true; - -var DEFINE_PROPERTY = "defineProperty"; -function define(O, key, value) { - O[key] || Object[DEFINE_PROPERTY](O, key, { - writable: true, - configurable: true, - value: value - }); -} - -define(String.prototype, "padLeft", "".padStart); -define(String.prototype, "padRight", "".padEnd); - -"pop,reverse,shift,keys,values,entries,indexOf,every,some,forEach,map,filter,find,findIndex,includes,join,slice,concat,push,splice,unshift,sort,lastIndexOf,reduce,reduceRight,copyWithin,fill".split(",").forEach(function (key) { - [][key] && define(Array, key, Function.call.bind([][key])); -}); -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(88))) - -/***/ }), -/* 119 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = undefined; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _consts = __webpack_require__(28); - -var _elements = __webpack_require__(47); - -var _elements2 = _interopRequireDefault(_elements); - -var _utils = __webpack_require__(41); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -var EMPTY_STRING = ''; - -var CHAT_SECTION_RIGHT_MAX = '280px'; -var CHAT_SECTION_RIGHT_MIN = '60px'; -var TOOLTIP_MEMBER_LIST = 'Member List'; -var TOOLTIP_CHANNEL_LEAVE = 'Channel Leave'; -var TOOLTIP_INVITE_MEMBER = 'Invite Member'; -var TITLE_CHAT_TITLE_DEFAULT = 'Group Channel'; -var TITLE_CHAT_TITLE_NEW_CHAT = 'New Chat'; -var TITLE_CHAT_LEAVE_POPUP = 'Do you really want to leave?'; -var TITLE_CHAT_LEAVE_BTN = 'Leave'; -var TITLE_CHAT_CANCEL_BTN = 'Cancel'; -var MEMBER_COUNT_DEFAULT = '0'; -var MARGIN_TOP_MESSAGE = '3px'; -var MESSAGE_NONE_IMAGE_HEIGHT = '10px'; -var DISPLAY_NONE = 'none'; -var TITLE_START_CHAT_BTN = 'Start Chat'; -var MESSAGE_CONTENT_HEIGHT_DEFAULT = 328; -var MESSAGE_INPUT_HEIGHT_DEFAULT = 29; -var MESSAGE_TYPING_SEVERAL = 'Several people are typing...'; -var MESSAGE_TYPING_MEMBER = ' is typing...'; -var DISPLAY_TYPE_INLINE_BLOCK = 'inline-block'; -var IMAGE_MAX_SIZE = 160; -var TEXT_FILE_DOWNLOAD = 'Download'; - -var ChatSection = function (_Element) { - _inherits(ChatSection, _Element); - - function ChatSection(widget) { - _classCallCheck(this, ChatSection); - - var _this = _possibleConstructorReturn(this, (ChatSection.__proto__ || Object.getPrototypeOf(ChatSection)).call(this)); - - _this._create(); - widget.appendChild(_this.self); - _this.textKr = ''; - return _this; - } - - _createClass(ChatSection, [{ - key: 'reset', - value: function reset() { - this._setContent(this.self, EMPTY_STRING); - } - }, { - key: '_create', - value: function _create() { - this.self = this.createDiv(); - this._setClass(this.self, [_consts.className.CHAT_SECTION]); - } - }, { - key: 'responsiveSize', - value: function responsiveSize(isMax, action) { - if (isMax !== undefined) { - this.self.style.right = isMax ? CHAT_SECTION_RIGHT_MIN : CHAT_SECTION_RIGHT_MAX; - } - action(); - } - }, { - key: '_getListBoardArray', - value: function _getListBoardArray() { - return Array.prototype.slice.call(this.self.childNodes, 0); - } - }, { - key: 'moveToFirstIndex', - value: function moveToFirstIndex(target) { - var _this2 = this; - - var items = this._getListBoardArray(); - items.filter(function (item) { - if (item.id == target.id) { - _this2.self.removeChild(item); - } - }); - this.self.insertBefore(target, this.self.firstChild); - } - }, { - key: 'setWidth', - value: function setWidth(width) { - this._setWidth(this.self, width); - } - - /* - Chat - */ - - }, { - key: 'createChatBoard', - value: function createChatBoard(channelUrl, isLast) { - var chatBoard = this.createDiv(); - this._setClass(chatBoard, [_consts.className.CHAT_BOARD]); - chatBoard.id = channelUrl ? channelUrl : ''; - - var chatTop = this.createDiv(); - this._setClass(chatTop, [_consts.className.TOP]); - - var chatTitle = this.createDiv(); - this._setClass(chatTitle, [_consts.className.TITLE]); - this._setContent(chatTitle, TITLE_CHAT_TITLE_DEFAULT); - chatBoard.topTitle = chatTitle; - chatTop.appendChild(chatTitle); - - var chatMemberCount = this.createDiv(); - this._setClass(chatMemberCount, [_consts.className.COUNT]); - this._setContent(chatMemberCount, MEMBER_COUNT_DEFAULT); - chatBoard.count = chatMemberCount; - chatTop.appendChild(chatMemberCount); - - var topBtnClose = this.createDiv(); - this._setClass(topBtnClose, [_consts.className.BTN, _consts.className.IC_CLOSE]); - chatBoard.closeBtn = topBtnClose; - chatTop.appendChild(topBtnClose); - - var topBtnLeave = this.createDiv(); - this._setClass(topBtnLeave, [_consts.className.BTN, _consts.className.IC_LEAVE]); - chatBoard.leaveBtn = topBtnLeave; - - var tooltipLeave = this.createSpan(); - this._setClass(tooltipLeave, [_consts.className.TOOLTIP]); - this._setContent(tooltipLeave, TOOLTIP_CHANNEL_LEAVE); - - topBtnLeave.appendChild(tooltipLeave); - chatTop.appendChild(topBtnLeave); - - var topBtnMembers = this.createDiv(); - this._setClass(topBtnMembers, [_consts.className.BTN, _consts.className.IC_MEMBERS]); - chatBoard.memberBtn = topBtnMembers; - - var tooltipMember = this.createSpan(); - this._setClass(tooltipMember, [_consts.className.TOOLTIP]); - this._setContent(tooltipMember, TOOLTIP_MEMBER_LIST); - - topBtnMembers.appendChild(tooltipMember); - chatTop.appendChild(topBtnMembers); - - var topBtnInvite = this.createDiv(); - this._setClass(topBtnInvite, [_consts.className.BTN, _consts.className.IC_INVITE]); - chatBoard.inviteBtn = topBtnInvite; - - var tooltipInvite = this.createSpan(); - this._setClass(tooltipInvite, [_consts.className.TOOLTIP]); - this._setContent(tooltipInvite, TOOLTIP_INVITE_MEMBER); - - topBtnInvite.appendChild(tooltipInvite); - chatTop.appendChild(topBtnInvite); - - chatBoard.appendChild(chatTop); - - var chatContent = this.createDiv(); - this._setClass(chatContent, [_consts.className.CONTENT]); - chatBoard.content = chatContent; - chatBoard.appendChild(chatContent); - - isLast ? this.self.appendChild(chatBoard) : this.moveToFirstIndex(chatBoard); - return chatBoard; - } - }, { - key: 'addLeavePopup', - value: function addLeavePopup(target) { - if (!target.leavePopup) { - var leavePopup = this.createDiv(); - this._setClass(leavePopup, [_consts.className.LEAVE_POPUP]); - - var leaveTitle = this.createDiv(); - this._setClass(leaveTitle, [_consts.className.POPUP_TOP]); - this._setContent(leaveTitle, TITLE_CHAT_LEAVE_POPUP); - leavePopup.appendChild(leaveTitle); - - var div = this.createDiv(); - var leaveBtn = this.createDiv(); - this._setClass(leaveBtn, [_consts.className.LEAVE_BTN]); - this._setContent(leaveBtn, TITLE_CHAT_LEAVE_BTN); - div.appendChild(leaveBtn); - - var cancelBtn = this.createDiv(); - this._setClickEvent(cancelBtn, function () { - target.removeChild(leavePopup); - target.leavePopup = null; - }); - this._setClass(cancelBtn, [_consts.className.CANCEL_BTN]); - this._setContent(cancelBtn, TITLE_CHAT_CANCEL_BTN); - div.appendChild(cancelBtn); - - leavePopup.appendChild(div); - - target.leavePopup = leavePopup; - target.leavePopup.leaveBtn = leaveBtn; - target.insertBefore(leavePopup, target.firstChild); - } - } - }, { - key: 'setLeaveBtnClickEvent', - value: function setLeaveBtnClickEvent(target, action) { - this._setClickEvent(target, action); - } - }, { - key: 'removeMemberPopup', - value: function removeMemberPopup() { - var items = this.self.querySelectorAll('.' + _consts.className.CHAT_BOARD); - for (var i = 0; i < items.length; i++) { - var item = items[i]; - (0, _utils.removeClass)(item.memberBtn, _consts.className.ACTIVE); - } - } - }, { - key: 'removeInvitePopup', - value: function removeInvitePopup() { - var items = this.self.querySelectorAll('.' + _consts.className.CHAT_BOARD); - for (var i = 0; i < items.length; i++) { - var item = items[i]; - (0, _utils.removeClass)(item.inviteBtn, _consts.className.ACTIVE); - } - } - }, { - key: 'addClickEvent', - value: function addClickEvent(target, action) { - this._setClickEvent(target, action); - } - }, { - key: 'updateChatTop', - value: function updateChatTop(target, count, title) { - this._setContent(target.count, count); - if (title !== null) { - this._setContent(target.topTitle, title); - } - } - }, { - key: 'getChatBoard', - value: function getChatBoard(channelUrl) { - var items = this.self.querySelectorAll('.' + _consts.className.CHAT_BOARD); - var targetBoard = void 0; - for (var i = 0; i < items.length; i++) { - var item = items[i]; - if (item.id == channelUrl) { - targetBoard = item; - break; - } - } - return targetBoard; - } - }, { - key: 'indexOfChatBord', - value: function indexOfChatBord(channelUrl) { - var items = this.self.querySelectorAll('.' + _consts.className.CHAT_BOARD); - var chatBoard = this.getChatBoard(channelUrl); - var index = -1; - for (var i = 0; i < items.length; i++) { - if (items[i] == chatBoard) { - index = i; - break; - } - } - return index; - } - }, { - key: 'closeChatBoard', - value: function closeChatBoard(target) { - target.parentNode.removeChild(target); - this.textKr = ''; - } - }, { - key: 'createMessageContent', - value: function createMessageContent(target) { - var chatContent = this.createDiv(); - this._setClass(chatContent, [_consts.className.CONTENT]); - - var messageContent = this.createDiv(); - this._setClass(messageContent, [_consts.className.MESSAGE_CONTENT]); - - var messageList = this.createDiv(); - this._setClass(messageList, [_consts.className.MESSAGE_LIST]); - messageContent.appendChild(messageList); - chatContent.appendChild(messageContent); - - var typingMessage = this.createDiv(); - this._setClass(typingMessage, [_consts.className.TYPING]); - chatContent.appendChild(typingMessage); - - var contentInput = this.createDiv(); - this._setClass(contentInput, [_consts.className.INPUT]); - - var chatText = this.createTextInput(); - contentInput.appendChild(chatText); - - var chatFile = this.createLabel(); - this._setClass(chatFile, [_consts.className.FILE]); - chatFile.setAttribute('for', 'file_' + target.id); - - var chatFileInput = this.createInput(); - chatFileInput.type = 'file'; - chatFileInput.name = 'file'; - chatFileInput.id = 'file_' + target.id; - (0, _utils.hide)(chatFileInput); - chatFile.appendChild(chatFileInput); - contentInput.appendChild(chatFile); - chatContent.appendChild(contentInput); - - target.content.parentNode.removeChild(target.content); - target.content = chatContent; - target.messageContent = messageContent; - target.list = messageList; - target.typing = typingMessage; - target.input = chatText; - target.file = chatFileInput; - target.appendChild(chatContent); - } - }, { - key: 'createTextInput', - value: function createTextInput() { - var chatText = this.createDiv(); - this._setClass(chatText, [_consts.className.TEXT]); - chatText.setAttribute('contenteditable', true); - return chatText; - } - }, { - key: 'clearInputText', - value: function clearInputText(target, channelUrl) { - var items = target.querySelectorAll(this.tagName.DIV); - for (var i = 0; i < items.length; i++) { - var item = items[i]; - item.remove(); - } - this._setContent(target, EMPTY_STRING); - this.responsiveHeight(channelUrl); - } - }, { - key: 'addPasteEvent', - value: function addPasteEvent(target, action) { - this._setPasteEvent(target, action); - } - }, { - key: 'addKeyUpEvent', - value: function addKeyUpEvent(target, action) { - this._setKeyupEvent(target, action); - } - }, { - key: 'addKeyDownEvent', - value: function addKeyDownEvent(target, action) { - this._setKeydownEvent(target, action); - } - }, { - key: 'addFileSelectEvent', - value: function addFileSelectEvent(target, action) { - this._setChangeEvent(target, action); - } - }, { - key: 'addScrollEvent', - value: function addScrollEvent(target, action) { - this._setScrollEvent(target, action); - } - }, { - key: 'responsiveHeight', - value: function responsiveHeight(channelUrl) { - var targetBoard = this.getChatBoard(channelUrl); - var messageContent = targetBoard.messageContent; - var changeHeight = (0, _utils.getFullHeight)(targetBoard.typing) + (0, _utils.getFullHeight)(targetBoard.input); - this._setHeight(messageContent, MESSAGE_CONTENT_HEIGHT_DEFAULT - (changeHeight - MESSAGE_INPUT_HEIGHT_DEFAULT)); - } - }, { - key: 'showTyping', - value: function showTyping(channel, spinner) { - var targetBoard = this.getChatBoard(channel.url); - var typing = targetBoard.typing; - if (!channel.isTyping()) { - this._setContent(typing, EMPTY_STRING); - (0, _utils.hide)(typing); - } else { - var typingUser = channel.getTypingMembers(); - spinner.insert(typing); - this._addContent(typing, typingUser.length > 1 ? MESSAGE_TYPING_SEVERAL : typingUser[0].nickname + MESSAGE_TYPING_MEMBER); - (0, _utils.show)(typing); - } - } - }, { - key: 'setImageSize', - value: function setImageSize(target, message) { - var _this3 = this; - - var imageResize = function imageResize(imageTarget, width, height) { - var scaleWidth = IMAGE_MAX_SIZE / width; - var scaleHeight = IMAGE_MAX_SIZE / height; - - var scale = scaleWidth <= scaleHeight ? scaleWidth : scaleHeight; - if (scale > 1) { - scale = 1; - } - - var resizeWidth = width * scale; - var resizeHeight = height * scale; - - _this3._setBackgroundSize(imageTarget, resizeWidth + 'px ' + resizeHeight + 'px'); - _this3._setWidth(imageTarget, resizeWidth); - _this3._setHeight(imageTarget, resizeHeight); - }; - - this._setBackgroundImage(target, message.thumbnails.length > 0 ? message.thumbnails[0].url : message.url); - if (message.thumbnails.length > 0) { - imageResize(target, message.thumbnails[0].real_width, message.thumbnails[0].real_height); - } else { - var img = new Image(); - img.addEventListener('load', function (res) { - res.path ? imageResize(target, res.path[0].width, res.path[0].height) : imageResize(target, res.target.width, res.target.height); - }); - img.src = message.url; - } - } - }, { - key: 'createMessageItem', - value: function createMessageItem(message, isCurrentUser, isContinue, unreadCount) { - var messageSet = this.createDiv(); - messageSet.id = message.messageId; - this._setClass(messageSet, isCurrentUser ? [_consts.className.MESSAGE_SET, _consts.className.USER] : [_consts.className.MESSAGE_SET]); - if (isContinue) { - messageSet.style.marginTop = MARGIN_TOP_MESSAGE; - } - - var senderImg = this.createDiv(); - this._setClass(senderImg, [_consts.className.IMAGE]); - var senderProfile = message.sender.profileUrl; - if (isContinue) { - senderProfile = ''; - senderImg.style.height = MESSAGE_NONE_IMAGE_HEIGHT; - } - senderImg.style.backgroundImage = 'url(' + senderProfile + ')'; - messageSet.appendChild(senderImg); - - var messageContent = this.createDiv(); - this._setClass(messageContent, [_consts.className.MESSAGE]); - - var senderNickname = this.createDiv(); - this._setClass(senderNickname, [_consts.className.NICKNAME]); - this._setContent(senderNickname, message.sender.nickname); - if (isContinue) { - senderNickname.style.display = DISPLAY_NONE; - } - messageContent.appendChild(senderNickname); - - var messageItem = this.createDiv(); - this._setClass(messageItem, [_consts.className.MESSAGE_ITEM]); - - var itemText = this.createDiv(); - if (message.isUserMessage()) { - this._setClass(itemText, [_consts.className.TEXT]); - this._setContent(itemText, message.message); - } else if (message.isFileMessage()) { - if (message.type.match(/^image\/gif$/)) { - this._setClass(itemText, [_consts.className.FILE_MESSAGE]); - var image = this.createImg(); - this._setClass(image, [_consts.className.IMAGE]); - image.src = message.url; - this.setImageSize(image, message); - itemText.appendChild(image); - } else { - this._setClass(itemText, [_consts.className.FILE_MESSAGE]); - var file = this.createA(); - file.href = message.url; - file.target = 'blank'; - if (message.type.match(/^image\/.+$/)) { - this._setClass(file, [_consts.className.IMAGE]); - this.setImageSize(file, message); - } else { - this._setClass(file, [_consts.className.FILE]); - var fileIcon = this.createDiv(); - this._setClass(fileIcon, [_consts.className.FILE_ICON]); - - var fileText = this.createDiv(); - this._setClass(fileText, [_consts.className.FILE_TEXT]); - - var fileName = this.createDiv(); - this._setClass(fileName, [_consts.className.FILE_NAME]); - this._setContent(fileName, message.name); - fileText.appendChild(fileName); - - var fileDownload = this.createDiv(); - this._setClass(fileDownload, [_consts.className.FILE_DOWNLOAD]); - this._setContent(fileDownload, TEXT_FILE_DOWNLOAD); - fileText.appendChild(fileDownload); - - file.appendChild(fileIcon); - file.appendChild(fileText); - } - itemText.appendChild(file); - } - } - - var itemUnread = this.createDiv(); - this._setClass(itemUnread, [_consts.className.UNREAD]); - this.setUnreadCount(itemUnread, unreadCount); - messageSet.unread = itemUnread; - - if (isCurrentUser) { - messageItem.appendChild(itemUnread); - messageItem.appendChild(itemText); - } else { - messageItem.appendChild(itemText); - messageItem.appendChild(itemUnread); - } - - messageContent.appendChild(messageItem); - messageSet.appendChild(messageContent); - return messageSet; - } - }, { - key: 'createAdminMessageItem', - value: function createAdminMessageItem(message) { - var admin = this.createDiv(); - this._setClass(admin, [_consts.className.MESSAGE_SET, _consts.className.ADMIN_MESSAGE]); - this._setContent(admin, message.message); - return admin; - } - }, { - key: 'setUnreadCount', - value: function setUnreadCount(target, count) { - count = parseInt(count); - this._setContent(target, count > 9 ? _consts.MAX_COUNT : count == 0 ? '' : count.toString()); - count > 0 ? (0, _utils.show)(target, DISPLAY_TYPE_INLINE_BLOCK) : (0, _utils.hide)(target); - } - }, { - key: 'updateReadReceipt', - value: function updateReadReceipt(channelSet, target) { - var items = target.querySelectorAll('.' + _consts.className.MESSAGE_SET); - for (var j = 0; j < channelSet.message.length; j++) { - var message = channelSet.message[j]; - for (var i = 0; i < items.length; i++) { - var item = items[i]; - if (item.id == message.messageId) { - this.setUnreadCount(item.unread, channelSet.channel.getReadReceipt(message)); - break; - } - } - } - } - }, { - key: 'createMessageItemTime', - value: function createMessageItemTime(date) { - var time = this.createDiv(); - this._setClass(time, [_consts.className.MESSAGE_SET, _consts.className.TIME]); - this._setContent(time, date); - return time; - } - }, { - key: 'createNewChatBoard', - value: function createNewChatBoard(target) { - var chatContent = this.createDiv(); - this._setClass(chatContent, [_consts.className.CONTENT]); - - var userContent = this.createDiv(); - this._setClass(userContent, [_consts.className.USER_CONTENT]); - chatContent.appendChild(userContent); - - var contentBottom = this.createDiv(); - this._setClass(contentBottom, [_consts.className.CONTENT_BOTTOM]); - - var contentBottomBtn = this.createDiv(); - this._setClass(contentBottomBtn, [_consts.className.NEW_CHAT_BTN, _consts.className.DISABLED]); - this._setContent(contentBottomBtn, TITLE_START_CHAT_BTN); - contentBottom.appendChild(contentBottomBtn); - chatContent.appendChild(contentBottom); - - target.content.parentNode.removeChild(target.content); - target.content = chatContent; - target.startBtn = contentBottomBtn; - target.userContent = userContent; - target.appendChild(chatContent); - this._setContent(target.topTitle, TITLE_CHAT_TITLE_NEW_CHAT); - } - }, { - key: 'createUserList', - value: function createUserList(target) { - if (target.querySelectorAll(this.tagName.UL).length == 0) { - var userList = this.createUl(); - target.list = userList; - target.appendChild(userList); - } - } - }, { - key: 'createUserListItem', - value: function createUserListItem(user) { - var li = this.createLi(); - - var userItem = this.createDiv(); - this._setClass(userItem, [_consts.className.USER_ITEM]); - - var userSelect = this.createDiv(); - this._setClass(userSelect, [_consts.className.USER_SELECT]); - this._setDataset(userSelect, 'user-id', user.userId); - li.select = userSelect; - userItem.appendChild(userSelect); - - var userProfile = this.createDiv(); - this._setClass(userProfile, [_consts.className.IMAGE]); - this._setBackgroundImage(userProfile, user.profileUrl); - userItem.appendChild(userProfile); - - var userNickname = this.createDiv(); - this._setClass(userNickname, [_consts.className.NICKNAME]); - this._setContent(userNickname, user.nickname); - userItem.appendChild(userNickname); - - li.appendChild(userItem); - return li; - } - }, { - key: 'getSelectedUserIds', - value: function getSelectedUserIds(target) { - var items = target.querySelectorAll('.' + _consts.className.ACTIVE); - var userIds = []; - for (var i = 0; i < items.length; i++) { - var item = items[i]; - userIds.push(item.getAttribute('data-user-id')); - } - return userIds; - } - }, { - key: 'isBottom', - value: function isBottom(targetContent, targetList) { - return this._isBottom(targetContent, targetList); - } - }, { - key: 'addUserListScrollEvent', - value: function addUserListScrollEvent(target, action) { - var _this4 = this; - - this._setScrollEvent(target.userContent, function () { - if (_this4.isBottom(target.userContent, target.userContent.list)) { - action(); - } - }); - } - }, { - key: 'scrollToBottom', - value: function scrollToBottom(target) { - target.scrollTop = target.scrollHeight - target.clientHeight; - } - }]); - - return ChatSection; -}(_elements2.default); - -exports.default = ChatSection; - -/***/ }), -/* 120 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = undefined; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _consts = __webpack_require__(28); - -var _utils = __webpack_require__(41); - -var _elements = __webpack_require__(47); - -var _elements2 = _interopRequireDefault(_elements); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -var EMPTY_STRING = ''; - -var OPTION_TOOLTIP_TEXT = 'Log out'; -var NEW_CHAT_TOOLTIP_TEXT = 'New Message'; - -var TITLE_TOP_LOGIN = 'SendBird Widget'; -var TITLE_TOP_CHANNEL = 'Channel List'; -var TITLE_LOGIN_USER_ID = 'USER ID'; -var TITLE_LOGIN_NICKNAME = 'NICKNAME'; -var TITLE_LOGIN_BTN = 'Start Chat'; -var TITLE_EMPTY_ITEM = 'Click below to start'; -var TITLE_EMPTY_BTN = 'Create'; - -var INPUT_TYPE = 'text'; -var INPUT_MAX_LENGTH = 20; - -var isLogoutClick = false; - -var ListBoard = function (_Element) { - _inherits(ListBoard, _Element); - - function ListBoard(widget) { - _classCallCheck(this, ListBoard); - - var _this = _possibleConstructorReturn(this, (ListBoard.__proto__ || Object.getPrototypeOf(ListBoard)).call(this)); - - _this._createBoard(); - widget.appendChild(_this.self); - - _this.createLoginForm(); - _this.createChannelListBoard(); - return _this; - } - - _createClass(ListBoard, [{ - key: 'reset', - value: function reset() { - this._setContent(this.list, EMPTY_STRING); - this._cleanLoginForm(); - } - }, { - key: '_createBoard', - value: function _createBoard() { - this.self = this.createDiv(); - this._setClass(this.self, [_consts.className.CHANNEL_BOARD]); - - var boardTop = this.createDiv(); - this._setClass(boardTop, [_consts.className.BOARD_TOP]); - - this.topTitle = this.createDiv(); - this._setClass(this.topTitle, [_consts.className.TITLE]); - this._setContent(this.topTitle, TITLE_TOP_LOGIN); - boardTop.appendChild(this.topTitle); - - this.btnMini = this.createDiv(); - this._setClass(this.btnMini, [_consts.className.BTN, _consts.className.IC_MINIMIZE]); - boardTop.appendChild(this.btnMini); - - this.btnOption = this.createDiv(); - this._setClass(this.btnOption, [_consts.className.BTN, _consts.className.IC_OPTION]); - - this.btnLogout = this.createDiv(); - this._setClass(this.btnLogout, [_consts.className.OPTION_MENU]); - var logoutText = this.createDiv(); - this._setClass(logoutText, [_consts.className.OPTION_CONTENT]); - this._setContent(logoutText, OPTION_TOOLTIP_TEXT); - this.btnLogout.appendChild(logoutText); - - this.btnOption.appendChild(this.btnLogout); - boardTop.appendChild(this.btnOption); - - this.addOptionClickEvent(); - - this.btnNewChat = this.createDiv(); - this._setClass(this.btnNewChat, [_consts.className.BTN, _consts.className.IC_NEW_CHAT]); - - var newChatTooltip = this.createSpan(); - this._setClass(newChatTooltip, [_consts.className.TOOLTIP]); - this._setContent(newChatTooltip, NEW_CHAT_TOOLTIP_TEXT); - this.btnNewChat.appendChild(newChatTooltip); - boardTop.appendChild(this.btnNewChat); - - this.self.appendChild(boardTop); - } - }, { - key: 'addMinimizeClickEvent', - value: function addMinimizeClickEvent(action) { - this._setClickEvent(this.btnMini, action); - } - }, { - key: 'addOptionClickEvent', - value: function addOptionClickEvent() { - var _this2 = this; - - if (!this._getOptionEventLock()) { - this._setClickEvent(this.btnOption, function () { - if ((0, _utils.hasClass)(_this2.btnOption, _consts.className.ACTIVE)) { - _this2.hideLogoutBtn(); - } else { - (0, _utils.addClass)(_this2.btnOption, _consts.className.ACTIVE); - (0, _utils.show)(_this2.btnLogout); - } - }); - } - } - }, { - key: 'addLogoutClickEvent', - value: function addLogoutClickEvent(action) { - this.setOptionEventLock(true); - this._setClickEvent(this.btnLogout, action); - } - }, { - key: 'setOptionEventLock', - value: function setOptionEventLock(value) { - isLogoutClick = value; - } - }, { - key: '_getOptionEventLock', - value: function _getOptionEventLock() { - return isLogoutClick; - } - }, { - key: 'hideLogoutBtn', - value: function hideLogoutBtn() { - (0, _utils.removeClass)(this.btnOption, _consts.className.ACTIVE); - (0, _utils.hide)(this.btnLogout); - } - }, { - key: 'addNewChatClickEvent', - value: function addNewChatClickEvent(action) { - this._setClickEvent(this.btnNewChat, action); - } - }, { - key: 'createLoginForm', - value: function createLoginForm() { - this.loginForm = this.createDiv(); - this._setClass(this.loginForm, [_consts.className.CONTENT, _consts.className.LOGIN_FORM]); - - var userIdEl = this.createDiv(); - this._setClass(userIdEl, [_consts.className.USER_ID]); - - var idTitle = this.createDiv(); - this._setClass(idTitle, [_consts.className.TITLE]); - this._setContent(idTitle, TITLE_LOGIN_USER_ID); - userIdEl.appendChild(idTitle); - - this.userId = this.createInput(); - this._setClass(this.userId, [_consts.className.INPUT]); - this.userId.type = INPUT_TYPE; - this.userId.maxlength = INPUT_MAX_LENGTH; - this.userId.title = TITLE_LOGIN_USER_ID; - this._setKeyupEvent(this.userId, this._toggleLoginBtn.bind(this)); - this._setChangeEvent(this.userId, this._toggleLoginBtn.bind(this)); - userIdEl.appendChild(this.userId); - this.loginForm.appendChild(userIdEl); - - var userNicknameEl = this.createDiv(); - this._setClass(userNicknameEl, [_consts.className.NICKNAME]); - - var nicknameTitle = this.createDiv(); - this._setClass(nicknameTitle, [_consts.className.TITLE]); - this._setContent(nicknameTitle, TITLE_LOGIN_NICKNAME); - userNicknameEl.appendChild(nicknameTitle); - - this.nickname = this.createInput(); - this._setClass(this.nickname, [_consts.className.INPUT]); - this.nickname.type = INPUT_TYPE; - this.nickname.maxlength = INPUT_MAX_LENGTH; - this.nickname.title = TITLE_LOGIN_NICKNAME; - this._setKeyupEvent(this.nickname, this._toggleLoginBtn.bind(this)); - this._setChangeEvent(this.nickname, this._toggleLoginBtn.bind(this)); - userNicknameEl.appendChild(this.nickname); - this.loginForm.appendChild(userNicknameEl); - - this.btnLogin = this.createDiv(); - this._setClass(this.btnLogin, [_consts.className.LOGIN_BTN]); - this._setContent(this.btnLogin, TITLE_LOGIN_BTN); - this.loginForm.appendChild(this.btnLogin); - } - }, { - key: 'showLoginForm', - value: function showLoginForm() { - if (this.self.lastElementChild == this.listContent) { - this.self.removeChild(this.listContent); - } - this._setContent(this.topTitle, TITLE_TOP_LOGIN); - (0, _utils.hide)(this.btnOption); - (0, _utils.hide)(this.btnNewChat); - this.self.appendChild(this.loginForm); - this._toggleLoginBtn(); - } - }, { - key: '_cleanLoginForm', - value: function _cleanLoginForm() { - this.userId.disabled = false; - this.nickname.disabled = false; - this._setUserId(EMPTY_STRING); - this._setNickname(EMPTY_STRING); - this._setContent(this.btnLogin, TITLE_LOGIN_BTN); - this.enabledToggle(this.btnLogin, true); - } - }, { - key: '_toggleLoginBtn', - value: function _toggleLoginBtn() { - if (!(0, _utils.isEmptyString)((0, _utils.removeWhiteSpace)(this.userId.value)) && !(0, _utils.isEmptyString)((0, _utils.removeWhiteSpace)(this.nickname.value))) { - if (this.btnLogin.innerHTML == TITLE_LOGIN_BTN) { - this.enabledToggle(this.btnLogin, true); - } - } else { - this.enabledToggle(this.btnLogin, false); - } - } - }, { - key: '_setUserId', - value: function _setUserId(value) { - this.userId.value = value; - } - }, { - key: 'getUserId', - value: function getUserId() { - return this.userId.value; - } - }, { - key: '_setNickname', - value: function _setNickname(value) { - this.nickname.value = value; - } - }, { - key: 'getNickname', - value: function getNickname() { - return this.nickname.value; - } - }, { - key: 'addLoginClickEvent', - value: function addLoginClickEvent(action) { - this._setClickEvent(this.btnLogin, action); - } - }, { - key: 'addKeyDownEvent', - value: function addKeyDownEvent(target, action) { - this._setKeydownEvent(target, action); - } - }, { - key: 'createChannelListBoard', - value: function createChannelListBoard() { - this.listContent = this.createDiv(); - this._setClass(this.listContent, [_consts.className.CONTENT, _consts.className.CHANNEL_LIST]); - - this.list = this.createUl(); - this.listContent.appendChild(this.list); - } - }, { - key: 'showChannelList', - value: function showChannelList() { - if (this.self.lastElementChild == this.loginForm) { - this.self.removeChild(this.loginForm); - this._cleanLoginForm(); - } - this._setContent(this.topTitle, TITLE_TOP_CHANNEL); - (0, _utils.show)(this.btnOption); - (0, _utils.show)(this.btnNewChat); - this.self.appendChild(this.listContent); - } - }, { - key: 'addChannelListScrollEvent', - value: function addChannelListScrollEvent(action) { - var _this3 = this; - - this._setScrollEvent(this.listContent, function () { - if (_this3._isBottom(_this3.listContent, _this3.list)) { - action(); - } - }); - } - }, { - key: 'createChannelItem', - value: function createChannelItem() { - var channelUrl = arguments.length <= 0 ? undefined : arguments[0]; - var coverUrl = arguments.length <= 1 ? undefined : arguments[1]; - var title = arguments.length <= 2 ? undefined : arguments[2]; - var time = arguments.length <= 3 ? undefined : arguments[3]; - var message = arguments.length <= 4 ? undefined : arguments[4]; - var unread = arguments.length <= 5 ? undefined : arguments[5]; - - var item = this.createDiv(); - this._setClass(item, [_consts.className.ITEM]); - var itemImg = this.createDiv(); - this._setClass(itemImg, [_consts.className.IMAGE]); - this._setBackgroundImage(itemImg, coverUrl); - item.appendChild(itemImg); - - var itemContent = this.createDiv(); - this._setClass(itemContent, [_consts.className.CONTENT]); - - var contentTop = this.createDiv(); - this._setClass(contentTop, [_consts.className.CONTENT_TOP]); - var contentTitle = this.createDiv(); - this._setClass(contentTitle, [_consts.className.TITLE]); - this._setContent(contentTitle, title); - contentTop.appendChild(contentTitle); - - var contentTime = this.createTime(); - this._setContent(contentTime, time); - contentTop.appendChild(contentTime); - - itemContent.appendChild(contentTop); - - var contentBottom = this.createDiv(); - this._setClass(contentBottom, [_consts.className.CONTENT_BOTTOM]); - var contentLastMessage = this.createDiv(); - this._setClass(contentLastMessage, [_consts.className.LAST_MESSAGE]); - this._setContent(contentLastMessage, message); - contentBottom.appendChild(contentLastMessage); - - var contentUnread = this.createSpan(); - this.setUnreadCount(contentUnread, unread); - contentBottom.appendChild(contentUnread); - - itemContent.appendChild(contentBottom); - - item.appendChild(itemContent); - - var li = this.createLi(); - this._setDataset(li, 'channel-url', channelUrl); - li.topTitle = contentTitle; - li.time = contentTime; - li.message = contentLastMessage; - li.unread = contentUnread; - li.appendChild(item); - - return li; - } - }, { - key: 'checkEmptyList', - value: function checkEmptyList() { - if (this.list.childNodes.length < 1) { - this._createEmptyItem(); - } else { - if (this.emptyItem) { - this.list.removeChild(this.emptyItem); - this.emptyItem = null; - } - } - } - }, { - key: '_createEmptyItem', - value: function _createEmptyItem() { - var _this4 = this; - - var emptyList = this.createDiv(); - this._setClass(emptyList, [_consts.className.EMPTY_ITEM]); - - var emptyTitle = this.createDiv(); - this._setClass(emptyTitle, [_consts.className.TITLE]); - this._setContent(emptyTitle, TITLE_EMPTY_ITEM); - - var emptyBtn = this.createDiv(); - this._setClickEvent(emptyBtn, function () { - _this4.btnNewChat.click(); - }); - this._setClass(emptyBtn, [_consts.className.NEW_CHAT_BTN]); - this._setContent(emptyBtn, TITLE_EMPTY_BTN); - - emptyList.appendChild(emptyTitle); - emptyList.appendChild(emptyBtn); - this.emptyItem = emptyList; - this.list.appendChild(emptyList); - } - }, { - key: 'setUnreadCount', - value: function setUnreadCount(target, count) { - count = parseInt(count); - this._setContent(target, count > 9 ? _consts.MAX_COUNT : count.toString()); - this._setFontSize(target, count > 9 ? _consts.MAX_FONT_ZISE : null); - count > 0 ? (0, _utils.show)(target) : (0, _utils.hide)(target); - } - }, { - key: 'addChannelClickEvent', - value: function addChannelClickEvent(target, action) { - this._setClickEvent(target, action); - } - }, { - key: '_getListItemsArray', - value: function _getListItemsArray() { - return Array.prototype.slice.call(this.list.childNodes, 0); - } - }, { - key: 'addListOnFirstIndex', - value: function addListOnFirstIndex(target) { - var _this5 = this; - - var items = this._getListItemsArray(); - items.filter(function (item) { - if (item.getAttribute('data-channel-url') == target.getAttribute('data-channel-url')) { - _this5.list.removeChild(item); - } - }); - this.list.insertBefore(target, this.list.firstChild); - } - }, { - key: 'getChannelItem', - value: function getChannelItem(channelUrl) { - var items = this._getListItemsArray(); - var targetChannel = void 0; - for (var i = 0; i < items.length; i++) { - var item = items[i]; - if (item.getAttribute('data-channel-url') == channelUrl) { - targetChannel = item; - break; - } - } - return targetChannel; - } - }, { - key: 'setChannelUnread', - value: function setChannelUnread(channelUrl, count) { - var target = this.getChannelItem(channelUrl); - if (target) { - this.setUnreadCount(target.unread, count); - } - } - }, { - key: 'setChannelLastMessage', - value: function setChannelLastMessage(channelUrl, message) { - var target = this.getChannelItem(channelUrl); - if (target) { - this._setContent(target.message, message); - } - } - }, { - key: 'setChannelLastMessageTime', - value: function setChannelLastMessageTime(channelUrl, time) { - var target = this.getChannelItem(channelUrl); - if (target) { - this._setContent(target.time, time); - } - } - }, { - key: 'setChannelTitle', - value: function setChannelTitle(channelUrl, name) { - var target = this.getChannelItem(channelUrl); - if (target) { - this._setContent(target.topTitle, name); - } - } - }]); - - return ListBoard; -}(_elements2.default); - -exports.default = ListBoard; - -/***/ }), -/* 121 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = undefined; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _consts = __webpack_require__(28); - -var _elements = __webpack_require__(47); - -var _elements2 = _interopRequireDefault(_elements); - -var _utils = __webpack_require__(41); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -var EMPTY_STRING = ''; -var TITLE_POPUP_MEMBER_LIST = 'Member List'; -var TITLE_POPUP_INVITE_LIST = 'Invite Members'; -var TITLE_POPUP_INVITE_BTN = 'Invite'; -var MEMBER_POPUP_DEFAULT = -30; -var INVITE_POPUP_DEFAULT = -3; -var POPUP_DISTANCE = 300; - -var Popup = function (_Element) { - _inherits(Popup, _Element); - - function Popup() { - _classCallCheck(this, Popup); - - var _this = _possibleConstructorReturn(this, (Popup.__proto__ || Object.getPrototypeOf(Popup)).call(this)); - - _this._createMemberPopup(); - _this._createInvitePopup(); - return _this; - } - - _createClass(Popup, [{ - key: 'reset', - value: function reset() { - this.closeMemberPopup(); - this.closeInvitePopup(); - } - }, { - key: 'closeMemberPopup', - value: function closeMemberPopup() { - (0, _utils.hide)(this.memberPopup); - this._setContent(this.memberPopup.list, EMPTY_STRING); - } - }, { - key: 'closeInvitePopup', - value: function closeInvitePopup() { - (0, _utils.hide)(this.invitePopup); - this._setContent(this.invitePopup.list, EMPTY_STRING); - this._setContent(this.invitePopup.count, '0'); - this._setContent(this.invitePopup.inviteBtn, TITLE_POPUP_INVITE_BTN); - (0, _utils.addClass)(this.invitePopup.inviteBtn, _consts.className.DISABLED); - } - }, { - key: 'showMemberPopup', - value: function showMemberPopup(chatSection, index) { - chatSection.appendChild(this.memberPopup); - this._setRight(this.memberPopup, MEMBER_POPUP_DEFAULT + index * POPUP_DISTANCE); - (0, _utils.show)(this.memberPopup); - } - }, { - key: 'showInvitePopup', - value: function showInvitePopup(chatSection, index) { - chatSection.appendChild(this.invitePopup); - this._setRight(this.invitePopup, INVITE_POPUP_DEFAULT + index * POPUP_DISTANCE); - (0, _utils.show)(this.invitePopup); - } - }, { - key: '_createMemberPopup', - value: function _createMemberPopup() { - this.memberPopup = this.createDiv(); - this._setClass(this.memberPopup, [_consts.className.POPUP, _consts.className.MEMBERS]); - - var popupBody = this.createDiv(); - this._setClass(popupBody, [_consts.className.POPUP_BODY]); - - var popupTop = this.createDiv(); - this._setClass(popupTop, [_consts.className.POPUP_TOP]); - - var topTitle = this.createDiv(); - this._setClass(topTitle, [_consts.className.TITLE]); - this._setContent(topTitle, TITLE_POPUP_MEMBER_LIST); - popupTop.appendChild(topTitle); - - var topCount = this.createDiv(); - this._setClass(topCount, [_consts.className.COUNT]); - this._setContent(topCount, '0'); - popupTop.appendChild(topCount); - - this.memberCloseBtn = this.createDiv(); - this._setClass(this.memberCloseBtn, [_consts.className.BTN, _consts.className.IC_CLOSE]); - popupTop.appendChild(this.memberCloseBtn); - - popupBody.appendChild(popupTop); - - var popupContent = this.createDiv(); - this._setClass(popupContent, [_consts.className.CONTENT]); - - var ul = this.createUl(); - popupContent.appendChild(ul); - - popupBody.appendChild(popupContent); - - this.memberPopup.list = ul; - this.memberPopup.count = topCount; - this.memberPopup.appendChild(popupBody); - } - }, { - key: 'updateCount', - value: function updateCount(target, count) { - count = parseInt(count); - this._setContent(target, count > 9 ? _consts.MAX_COUNT : count.toString()); - } - }, { - key: 'createMemberItem', - value: function createMemberItem(member, isInvite, isCurrentUser) { - var li = this.createLi(); - var div = this.createDiv(); - - if (isInvite) { - var userSelect = this.createDiv(); - this._setClass(userSelect, [_consts.className.USER_SELECT]); - this._setDataset(userSelect, 'user-id', member.userId); - li.select = userSelect; - div.appendChild(userSelect); - } - - if (isCurrentUser) { - var userProfileMe = this.createDiv(); - this._setClass(userProfileMe, [_consts.className.IMAGE_ME]); - div.appendChild(userProfileMe); - } - - var userProfile = this.createDiv(); - this._setClass(userProfile, [_consts.className.IMAGE]); - this._setBackgroundImage(userProfile, member.profileUrl); - div.appendChild(userProfile); - - var userNickname = this.createDiv(); - this._setClass(userNickname, [_consts.className.NICKNAME]); - this._setContent(userNickname, member.nickname); - div.appendChild(userNickname); - - li.appendChild(div); - return li; - } - }, { - key: '_createInvitePopup', - value: function _createInvitePopup() { - this.invitePopup = this.createDiv(); - this._setClass(this.invitePopup, [_consts.className.POPUP, _consts.className.INVITE]); - - var popupBody = this.createDiv(); - this._setClass(popupBody, [_consts.className.POPUP_BODY]); - - var popupContent = this.createDiv(); - this._setClass(popupContent, [_consts.className.CONTENT]); - - var ul = this.createUl(); - popupContent.appendChild(ul); - popupBody.appendChild(popupContent); - - var popupBottom = this.createDiv(); - this._setClass(popupBottom, [_consts.className.POPUP_BOTTOM]); - - var bottomTitle = this.createDiv(); - this._setClass(bottomTitle, [_consts.className.TITLE]); - this._setContent(bottomTitle, TITLE_POPUP_INVITE_LIST); - popupBottom.appendChild(bottomTitle); - - var bottomCount = this.createDiv(); - this._setClass(bottomCount, [_consts.className.COUNT]); - this._setContent(bottomCount, '0'); - popupBottom.appendChild(bottomCount); - - var bottomInvite = this.createDiv(); - this._setClass(bottomInvite, [_consts.className.INVITE_BTN, _consts.className.DISABLED]); - this._setContent(bottomInvite, TITLE_POPUP_INVITE_BTN); - popupBottom.appendChild(bottomInvite); - - popupBody.appendChild(popupBottom); - this.invitePopup.content = popupContent; - this.invitePopup.list = ul; - this.invitePopup.count = bottomCount; - this.invitePopup.inviteBtn = bottomInvite; - this.invitePopup.appendChild(popupBody); - } - }, { - key: 'getSelectedUserIds', - value: function getSelectedUserIds(target) { - var items = target.querySelectorAll('.' + _consts.className.ACTIVE); - var userIds = []; - for (var i = 0; i < items.length; i++) { - var item = items[i]; - userIds.push(item.getAttribute('data-user-id')); - } - return userIds; - } - }, { - key: 'addCloseBtnClickEvent', - value: function addCloseBtnClickEvent(action) { - this._setClickEvent(this.memberCloseBtn, function () { - action(); - }); - } - }, { - key: 'addScrollEvent', - value: function addScrollEvent(action) { - var _this2 = this; - - this._setScrollEvent(this.invitePopup.content, function () { - if (_this2._isBottom(_this2.invitePopup.content, _this2.invitePopup.list)) { - action(); - } - }); - } - }, { - key: 'addClickEvent', - value: function addClickEvent(target, action) { - this._setClickEvent(target, action); - } - }]); - - return Popup; -}(_elements2.default); - -exports.default = Popup; - -/***/ }), -/* 122 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = undefined; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _consts = __webpack_require__(28); - -var _elements = __webpack_require__(47); - -var _elements2 = _interopRequireDefault(_elements); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -var EMPTY_STRING = ''; - -var Spinner = function (_Element) { - _inherits(Spinner, _Element); - - function Spinner() { - _classCallCheck(this, Spinner); - - var _this = _possibleConstructorReturn(this, (Spinner.__proto__ || Object.getPrototypeOf(Spinner)).call(this)); - - _this._create(); - return _this; - } - - _createClass(Spinner, [{ - key: '_create', - value: function _create() { - this.self = this.createDiv(); - this._setClass(this.self, [_consts.className.SPINNER]); - var i; - for (i = 0; i < 3; i++) { - this.self.appendChild(this.createDiv()); - } - } - }, { - key: 'insert', - value: function insert(target) { - this._setContent(target, EMPTY_STRING); - target.appendChild(this.self); - } - }, { - key: 'remove', - value: function remove(target) { - if (target.firstElementChild) { - target.removeChild(this.self); - } - } - }]); - - return Spinner; -}(_elements2.default); - -exports.default = Spinner; - -/***/ }), -/* 123 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = undefined; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _consts = __webpack_require__(28); - -var _elements = __webpack_require__(47); - -var _elements2 = _interopRequireDefault(_elements); - -var _utils = __webpack_require__(41); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -var WidgetBtn = function (_Element) { - _inherits(WidgetBtn, _Element); - - function WidgetBtn(widget) { - _classCallCheck(this, WidgetBtn); - - var _this = _possibleConstructorReturn(this, (WidgetBtn.__proto__ || Object.getPrototypeOf(WidgetBtn)).call(this)); - - _this._create(); - widget.appendChild(_this.self); - return _this; - } - - _createClass(WidgetBtn, [{ - key: 'reset', - value: function reset() { - this.toggleIcon(false); - this.setUnreadCount(0); - } - }, { - key: '_create', - value: function _create() { - this.self = this.createDiv(); - this._setClass(this.self, [_consts.className.WIDGET_BTN, _consts.className.IC_LOGIN]); - - this.unread = this.createDiv(); - this._setClass(this.unread, [_consts.className.NOTIFICATION]); - - this.self.appendChild(this.unread); - } - }, { - key: 'addClickEvent', - value: function addClickEvent(action) { - this._setClickEvent(this.self, action); - } - }, { - key: 'setUnreadCount', - value: function setUnreadCount(count) { - count = parseInt(count); - this._setContent(this.unread, count > 9 ? _consts.MAX_COUNT : count.toString()); - count > 0 ? (0, _utils.show)(this.unread) : (0, _utils.hide)(this.unread); - } - }, { - key: 'toggleIcon', - value: function toggleIcon(isConnected) { - isConnected ? (0, _utils.addClass)((0, _utils.removeClass)(this.self, _consts.className.IC_LOGIN), _consts.className.IC_CONNECTED) : (0, _utils.addClass)((0, _utils.removeClass)(this.self, _consts.className.IC_CONNECTED), _consts.className.IC_LOGIN); - } - }]); - - return WidgetBtn; -}(_elements2.default); - -exports.default = WidgetBtn; - -/***/ }), -/* 124 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = undefined; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _consts = __webpack_require__(28); - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var GLOBAL_HANDLER = 'GLOBAL_HANDLER'; -var GET_MESSAGE_LIMIT = 20; - -var Sendbird = function () { - function Sendbird(appId) { - _classCallCheck(this, Sendbird); - - this.sb = new window.SendBird({ appId: appId }); - this.channelListQuery = null; - this.userListQuery = null; - } - - _createClass(Sendbird, [{ - key: 'reset', - value: function reset() { - this.channelListQuery = null; - this.userListQuery = null; - this.sb.removeChannelHandler(GLOBAL_HANDLER); - } - }, { - key: 'isConnected', - value: function isConnected() { - return !!this.sb.currentUser; - } - }, { - key: 'connect', - value: function connect(userId, nickname, action) { - var _this = this; - - this.sb.connect(userId.trim(), function (user, error) { - if (error) { - console.error(error); - return; - } - _this.sb.updateCurrentUserInfo(nickname.trim(), '', function (response, error) { - if (error) { - console.error(error); - return; - } - action(); - }); - }); - } - }, { - key: 'disconnect', - value: function disconnect(action) { - if (this.isConnected()) { - this.sb.disconnect(function () { - action(); - }); - } - } - }, { - key: 'isCurrentUser', - value: function isCurrentUser(user) { - return this.sb.currentUser.userId == user.userId; - } - - /* - Channel - */ - - }, { - key: 'getChannelList', - value: function getChannelList(action) { - if (!this.channelListQuery) { - this.channelListQuery = this.sb.GroupChannel.createMyGroupChannelListQuery(); - this.channelListQuery.includeEmpty = true; - this.channelListQuery.limit = 20; - } - if (this.channelListQuery.hasNext && !this.channelListQuery.isLoading) { - this.channelListQuery.next(function (channelList, error) { - if (error) { - console.error(error); - return; - } - action(channelList); - }); - } - } - }, { - key: 'getChannelInfo', - value: function getChannelInfo(channelUrl, action) { - this.sb.GroupChannel.getChannel(channelUrl, function (channel, error) { - if (error) { - console.error(error); - return; - } - action(channel); - }); - } - }, { - key: 'createNewChannel', - value: function createNewChannel(userIds, action) { - this.sb.GroupChannel.createChannelWithUserIds(userIds, true, '', '', '', function (channel, error) { - if (error) { - console.error(error); - return; - } - action(channel); - }); - } - }, { - key: 'inviteMember', - value: function inviteMember(channel, userIds, action) { - channel.inviteWithUserIds(userIds, function (response, error) { - if (error) { - console.error(error); - return; - } - action(); - }); - } - }, { - key: 'channelLeave', - value: function channelLeave(channel, action) { - channel.leave(function (response, error) { - if (error) { - console.error(error); - return; - } - action(); - }); - } - - /* - Message - */ - - }, { - key: 'getTotalUnreadCount', - value: function getTotalUnreadCount(action) { - this.sb.GroupChannel.getTotalUnreadMessageCount(function (unreadCount) { - action(unreadCount); - }); - } - }, { - key: 'getMessageList', - value: function getMessageList(channelSet, action) { - if (!channelSet.query) { - channelSet.query = channelSet.channel.createPreviousMessageListQuery(); - } - if (channelSet.query.hasMore && !channelSet.query.isLoading) { - channelSet.query.load(GET_MESSAGE_LIMIT, false, function (messageList, error) { - if (error) { - console.error(error); - return; - } - action(messageList); - }); - } - } - }, { - key: 'sendTextMessage', - value: function sendTextMessage(channel, textMessage, action) { - channel.sendUserMessage(textMessage, function (message, error) { - if (error) { - console.error(error); - return; - } - action(message); - }); - } - }, { - key: 'sendFileMessage', - value: function sendFileMessage(channel, file, action) { - var thumbSize = []; - if (file.type.match(/^image\/.+$/)) { - thumbSize = [{ 'maxWidth': 160, 'maxHeight': 160 }]; - } - channel.sendFileMessage(file, '', '', thumbSize, function (message, error) { - if (error) { - console.error(error); - return; - } - action(message); - }); - } - - /* - User - */ - - }, { - key: 'getUserList', - value: function getUserList(action) { - if (!this.userListQuery) { - this.userListQuery = this.sb.createUserListQuery(); - } - if (this.userListQuery.hasNext && !this.userListQuery.isLoading) { - this.userListQuery.next(function (userList, error) { - if (error) { - console.error(error); - return; - } - action(userList); - }); - } - } - - /* - Handler - */ - - }, { - key: 'createHandlerGlobal', - value: function createHandlerGlobal() { - var messageReceivedFunc = arguments.length <= 0 ? undefined : arguments[0]; - var ChannelChangedFunc = arguments.length <= 1 ? undefined : arguments[1]; - var typingStatusFunc = arguments.length <= 2 ? undefined : arguments[2]; - var readReceiptFunc = arguments.length <= 3 ? undefined : arguments[3]; - var userLeftFunc = arguments.length <= 4 ? undefined : arguments[4]; - var userJoinFunc = arguments.length <= 5 ? undefined : arguments[5]; - - var channelHandler = new this.sb.ChannelHandler(); - channelHandler.onMessageReceived = function (channel, message) { - messageReceivedFunc(channel, message); - }; - channelHandler.onChannelChanged = function (channel) { - ChannelChangedFunc(channel); - }; - channelHandler.onTypingStatusUpdated = function (channel) { - typingStatusFunc(channel); - }; - channelHandler.onReadReceiptUpdated = function (channel) { - readReceiptFunc(channel); - }; - channelHandler.onUserLeft = function (channel, user) { - userLeftFunc(channel, user); - }; - channelHandler.onUserJoined = function (channel, user) { - userJoinFunc(channel, user); - }; - this.sb.addChannelHandler(GLOBAL_HANDLER, channelHandler); - } - - /* - Info - */ - - }, { - key: 'getNicknamesString', - value: function getNicknamesString(channel) { - var nicknameList = []; - var currentUserId = this.sb.currentUser.userId; - channel.members.forEach(function (member) { - if (member.userId != currentUserId) { - nicknameList.push(member.nickname); - } - }); - return nicknameList.toString(); - } - }, { - key: 'getMemberCount', - value: function getMemberCount(channel) { - return channel.memberCount > 9 ? _consts.MAX_COUNT : channel.memberCount.toString(); - } - }, { - key: 'getLastMessage', - value: function getLastMessage(channel) { - if (channel.lastMessage) { - return channel.lastMessage.isUserMessage() ? channel.lastMessage.message : channel.lastMessage.name; - } - return ''; - } - }, { - key: 'getMessageTime', - value: function getMessageTime(message) { - var months = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC']; - - var _getDay = function _getDay(val) { - var day = parseInt(val); - if (day == 1) { - return day + 'st'; - } else if (day == 2) { - return day + 'en'; - } else if (day == 3) { - return day + 'rd'; - } else { - return day + 'th'; - } - }; - - var _checkTime = function _checkTime(val) { - return +val < 10 ? '0' + val : val; - }; - - if (message) { - var LAST_MESSAGE_YESTERDAY = 'YESTERDAY'; - var _nowDate = new Date(); - var _date = new Date(message.createdAt); - if (_nowDate.getDate() - _date.getDate() == 1) { - return LAST_MESSAGE_YESTERDAY; - } else if (_nowDate.getFullYear() == _date.getFullYear() && _nowDate.getMonth() == _date.getMonth() && _nowDate.getDate() == _date.getDate()) { - return _checkTime(_date.getHours()) + ':' + _checkTime(_date.getMinutes()); - } else { - return months[_date.getMonth()] + ' ' + _getDay(_date.getDate()); - } - } - return ''; - } - }, { - key: 'getMessageReadReceiptCount', - value: function getMessageReadReceiptCount(channel, message) { - return channel.getReadReceipt(message); - } - }, { - key: 'getChannelUnreadCount', - value: function getChannelUnreadCount(channel) { - return channel.unreadMessageCount; - } - }]); - - return Sendbird; -}(); - -exports.default = Sendbird; - -/***/ }), -/* 125 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -exports.byteLength = byteLength -exports.toByteArray = toByteArray -exports.fromByteArray = fromByteArray - -var lookup = [] -var revLookup = [] -var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array - -var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' -for (var i = 0, len = code.length; i < len; ++i) { - lookup[i] = code[i] - revLookup[code.charCodeAt(i)] = i -} - -revLookup['-'.charCodeAt(0)] = 62 -revLookup['_'.charCodeAt(0)] = 63 - -function placeHoldersCount (b64) { - var len = b64.length - if (len % 4 > 0) { - throw new Error('Invalid string. Length must be a multiple of 4') - } - - // the number of equal signs (place holders) - // if there are two placeholders, than the two characters before it - // represent one byte - // if there is only one, then the three characters before it represent 2 bytes - // this is just a cheap hack to not do indexOf twice - return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0 -} - -function byteLength (b64) { - // base64 is 4/3 + up to two characters of the original data - return b64.length * 3 / 4 - placeHoldersCount(b64) -} - -function toByteArray (b64) { - var i, j, l, tmp, placeHolders, arr - var len = b64.length - placeHolders = placeHoldersCount(b64) - - arr = new Arr(len * 3 / 4 - placeHolders) - - // if there are placeholders, only get up to the last complete 4 chars - l = placeHolders > 0 ? len - 4 : len - - var L = 0 - - for (i = 0, j = 0; i < l; i += 4, j += 3) { - tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)] - arr[L++] = (tmp >> 16) & 0xFF - arr[L++] = (tmp >> 8) & 0xFF - arr[L++] = tmp & 0xFF - } - - if (placeHolders === 2) { - tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4) - arr[L++] = tmp & 0xFF - } else if (placeHolders === 1) { - tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2) - arr[L++] = (tmp >> 8) & 0xFF - arr[L++] = tmp & 0xFF - } - - return arr -} - -function tripletToBase64 (num) { - return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F] -} - -function encodeChunk (uint8, start, end) { - var tmp - var output = [] - for (var i = start; i < end; i += 3) { - tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) - output.push(tripletToBase64(tmp)) - } - return output.join('') -} - -function fromByteArray (uint8) { - var tmp - var len = uint8.length - var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes - var output = '' - var parts = [] - var maxChunkLength = 16383 // must be multiple of 3 - - // go through the array every three bytes, we'll deal with trailing stuff later - for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { - parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) - } - - // pad the end with zeros, but make sure to not forget the extra bytes - if (extraBytes === 1) { - tmp = uint8[len - 1] - output += lookup[tmp >> 2] - output += lookup[(tmp << 4) & 0x3F] - output += '==' - } else if (extraBytes === 2) { - tmp = (uint8[len - 2] << 8) + (uint8[len - 1]) - output += lookup[tmp >> 10] - output += lookup[(tmp >> 4) & 0x3F] - output += lookup[(tmp << 2) & 0x3F] - output += '=' - } - - parts.push(output) - - return parts.join('') -} - - -/***/ }), -/* 126 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) {/*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - */ -/* eslint-disable no-proto */ - - - -var base64 = __webpack_require__(125) -var ieee754 = __webpack_require__(310) -var isArray = __webpack_require__(311) - -exports.Buffer = Buffer -exports.SlowBuffer = SlowBuffer -exports.INSPECT_MAX_BYTES = 50 - -/** - * If `Buffer.TYPED_ARRAY_SUPPORT`: - * === true Use Uint8Array implementation (fastest) - * === false Use Object implementation (most compatible, even IE6) - * - * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, - * Opera 11.6+, iOS 4.2+. - * - * Due to various browser bugs, sometimes the Object implementation will be used even - * when the browser supports typed arrays. - * - * Note: - * - * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, - * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. - * - * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. - * - * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of - * incorrect length in some situations. - - * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they - * get the Object implementation, which is slower but behaves correctly. - */ -Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined - ? global.TYPED_ARRAY_SUPPORT - : typedArraySupport() - -/* - * Export kMaxLength after typed array support is determined. - */ -exports.kMaxLength = kMaxLength() - -function typedArraySupport () { - try { - var arr = new Uint8Array(1) - arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }} - return arr.foo() === 42 && // typed array instances can be augmented - typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` - arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray` - } catch (e) { - return false - } -} - -function kMaxLength () { - return Buffer.TYPED_ARRAY_SUPPORT - ? 0x7fffffff - : 0x3fffffff -} - -function createBuffer (that, length) { - if (kMaxLength() < length) { - throw new RangeError('Invalid typed array length') - } - if (Buffer.TYPED_ARRAY_SUPPORT) { - // Return an augmented `Uint8Array` instance, for best performance - that = new Uint8Array(length) - that.__proto__ = Buffer.prototype - } else { - // Fallback: Return an object instance of the Buffer class - if (that === null) { - that = new Buffer(length) - } - that.length = length - } - - return that -} - -/** - * The Buffer constructor returns instances of `Uint8Array` that have their - * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of - * `Uint8Array`, so the returned instances will have all the node `Buffer` methods - * and the `Uint8Array` methods. Square bracket notation works as expected -- it - * returns a single octet. - * - * The `Uint8Array` prototype remains unmodified. - */ - -function Buffer (arg, encodingOrOffset, length) { - if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) { - return new Buffer(arg, encodingOrOffset, length) - } - - // Common case. - if (typeof arg === 'number') { - if (typeof encodingOrOffset === 'string') { - throw new Error( - 'If encoding is specified then the first argument must be a string' - ) - } - return allocUnsafe(this, arg) - } - return from(this, arg, encodingOrOffset, length) -} - -Buffer.poolSize = 8192 // not used by this implementation - -// TODO: Legacy, not needed anymore. Remove in next major version. -Buffer._augment = function (arr) { - arr.__proto__ = Buffer.prototype - return arr -} - -function from (that, value, encodingOrOffset, length) { - if (typeof value === 'number') { - throw new TypeError('"value" argument must not be a number') - } - - if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) { - return fromArrayBuffer(that, value, encodingOrOffset, length) - } - - if (typeof value === 'string') { - return fromString(that, value, encodingOrOffset) - } - - return fromObject(that, value) -} - -/** - * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError - * if value is a number. - * Buffer.from(str[, encoding]) - * Buffer.from(array) - * Buffer.from(buffer) - * Buffer.from(arrayBuffer[, byteOffset[, length]]) - **/ -Buffer.from = function (value, encodingOrOffset, length) { - return from(null, value, encodingOrOffset, length) -} - -if (Buffer.TYPED_ARRAY_SUPPORT) { - Buffer.prototype.__proto__ = Uint8Array.prototype - Buffer.__proto__ = Uint8Array - if (typeof Symbol !== 'undefined' && Symbol.species && - Buffer[Symbol.species] === Buffer) { - // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 - Object.defineProperty(Buffer, Symbol.species, { - value: null, - configurable: true - }) - } -} - -function assertSize (size) { - if (typeof size !== 'number') { - throw new TypeError('"size" argument must be a number') - } else if (size < 0) { - throw new RangeError('"size" argument must not be negative') - } -} - -function alloc (that, size, fill, encoding) { - assertSize(size) - if (size <= 0) { - return createBuffer(that, size) - } - if (fill !== undefined) { - // Only pay attention to encoding if it's a string. This - // prevents accidentally sending in a number that would - // be interpretted as a start offset. - return typeof encoding === 'string' - ? createBuffer(that, size).fill(fill, encoding) - : createBuffer(that, size).fill(fill) - } - return createBuffer(that, size) -} - -/** - * Creates a new filled Buffer instance. - * alloc(size[, fill[, encoding]]) - **/ -Buffer.alloc = function (size, fill, encoding) { - return alloc(null, size, fill, encoding) -} - -function allocUnsafe (that, size) { - assertSize(size) - that = createBuffer(that, size < 0 ? 0 : checked(size) | 0) - if (!Buffer.TYPED_ARRAY_SUPPORT) { - for (var i = 0; i < size; ++i) { - that[i] = 0 - } - } - return that -} - -/** - * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. - * */ -Buffer.allocUnsafe = function (size) { - return allocUnsafe(null, size) -} -/** - * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. - */ -Buffer.allocUnsafeSlow = function (size) { - return allocUnsafe(null, size) -} - -function fromString (that, string, encoding) { - if (typeof encoding !== 'string' || encoding === '') { - encoding = 'utf8' - } - - if (!Buffer.isEncoding(encoding)) { - throw new TypeError('"encoding" must be a valid string encoding') - } - - var length = byteLength(string, encoding) | 0 - that = createBuffer(that, length) - - var actual = that.write(string, encoding) - - if (actual !== length) { - // Writing a hex string, for example, that contains invalid characters will - // cause everything after the first invalid character to be ignored. (e.g. - // 'abxxcd' will be treated as 'ab') - that = that.slice(0, actual) - } - - return that -} - -function fromArrayLike (that, array) { - var length = array.length < 0 ? 0 : checked(array.length) | 0 - that = createBuffer(that, length) - for (var i = 0; i < length; i += 1) { - that[i] = array[i] & 255 - } - return that -} - -function fromArrayBuffer (that, array, byteOffset, length) { - array.byteLength // this throws if `array` is not a valid ArrayBuffer - - if (byteOffset < 0 || array.byteLength < byteOffset) { - throw new RangeError('\'offset\' is out of bounds') - } - - if (array.byteLength < byteOffset + (length || 0)) { - throw new RangeError('\'length\' is out of bounds') - } - - if (byteOffset === undefined && length === undefined) { - array = new Uint8Array(array) - } else if (length === undefined) { - array = new Uint8Array(array, byteOffset) - } else { - array = new Uint8Array(array, byteOffset, length) - } - - if (Buffer.TYPED_ARRAY_SUPPORT) { - // Return an augmented `Uint8Array` instance, for best performance - that = array - that.__proto__ = Buffer.prototype - } else { - // Fallback: Return an object instance of the Buffer class - that = fromArrayLike(that, array) - } - return that -} - -function fromObject (that, obj) { - if (Buffer.isBuffer(obj)) { - var len = checked(obj.length) | 0 - that = createBuffer(that, len) - - if (that.length === 0) { - return that - } - - obj.copy(that, 0, 0, len) - return that - } - - if (obj) { - if ((typeof ArrayBuffer !== 'undefined' && - obj.buffer instanceof ArrayBuffer) || 'length' in obj) { - if (typeof obj.length !== 'number' || isnan(obj.length)) { - return createBuffer(that, 0) - } - return fromArrayLike(that, obj) - } - - if (obj.type === 'Buffer' && isArray(obj.data)) { - return fromArrayLike(that, obj.data) - } - } - - throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.') -} - -function checked (length) { - // Note: cannot use `length < kMaxLength()` here because that fails when - // length is NaN (which is otherwise coerced to zero.) - if (length >= kMaxLength()) { - throw new RangeError('Attempt to allocate Buffer larger than maximum ' + - 'size: 0x' + kMaxLength().toString(16) + ' bytes') - } - return length | 0 -} - -function SlowBuffer (length) { - if (+length != length) { // eslint-disable-line eqeqeq - length = 0 - } - return Buffer.alloc(+length) -} - -Buffer.isBuffer = function isBuffer (b) { - return !!(b != null && b._isBuffer) -} - -Buffer.compare = function compare (a, b) { - if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { - throw new TypeError('Arguments must be Buffers') - } - - if (a === b) return 0 - - var x = a.length - var y = b.length - - for (var i = 0, len = Math.min(x, y); i < len; ++i) { - if (a[i] !== b[i]) { - x = a[i] - y = b[i] - break - } - } - - if (x < y) return -1 - if (y < x) return 1 - return 0 -} - -Buffer.isEncoding = function isEncoding (encoding) { - switch (String(encoding).toLowerCase()) { - case 'hex': - case 'utf8': - case 'utf-8': - case 'ascii': - case 'latin1': - case 'binary': - case 'base64': - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return true - default: - return false - } -} - -Buffer.concat = function concat (list, length) { - if (!isArray(list)) { - throw new TypeError('"list" argument must be an Array of Buffers') - } - - if (list.length === 0) { - return Buffer.alloc(0) - } - - var i - if (length === undefined) { - length = 0 - for (i = 0; i < list.length; ++i) { - length += list[i].length - } - } - - var buffer = Buffer.allocUnsafe(length) - var pos = 0 - for (i = 0; i < list.length; ++i) { - var buf = list[i] - if (!Buffer.isBuffer(buf)) { - throw new TypeError('"list" argument must be an Array of Buffers') - } - buf.copy(buffer, pos) - pos += buf.length - } - return buffer -} - -function byteLength (string, encoding) { - if (Buffer.isBuffer(string)) { - return string.length - } - if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' && - (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) { - return string.byteLength - } - if (typeof string !== 'string') { - string = '' + string - } - - var len = string.length - if (len === 0) return 0 - - // Use a for loop to avoid recursion - var loweredCase = false - for (;;) { - switch (encoding) { - case 'ascii': - case 'latin1': - case 'binary': - return len - case 'utf8': - case 'utf-8': - case undefined: - return utf8ToBytes(string).length - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return len * 2 - case 'hex': - return len >>> 1 - case 'base64': - return base64ToBytes(string).length - default: - if (loweredCase) return utf8ToBytes(string).length // assume utf8 - encoding = ('' + encoding).toLowerCase() - loweredCase = true - } - } -} -Buffer.byteLength = byteLength - -function slowToString (encoding, start, end) { - var loweredCase = false - - // No need to verify that "this.length <= MAX_UINT32" since it's a read-only - // property of a typed array. - - // This behaves neither like String nor Uint8Array in that we set start/end - // to their upper/lower bounds if the value passed is out of range. - // undefined is handled specially as per ECMA-262 6th Edition, - // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. - if (start === undefined || start < 0) { - start = 0 - } - // Return early if start > this.length. Done here to prevent potential uint32 - // coercion fail below. - if (start > this.length) { - return '' - } - - if (end === undefined || end > this.length) { - end = this.length - } - - if (end <= 0) { - return '' - } - - // Force coersion to uint32. This will also coerce falsey/NaN values to 0. - end >>>= 0 - start >>>= 0 - - if (end <= start) { - return '' - } - - if (!encoding) encoding = 'utf8' - - while (true) { - switch (encoding) { - case 'hex': - return hexSlice(this, start, end) - - case 'utf8': - case 'utf-8': - return utf8Slice(this, start, end) - - case 'ascii': - return asciiSlice(this, start, end) - - case 'latin1': - case 'binary': - return latin1Slice(this, start, end) - - case 'base64': - return base64Slice(this, start, end) - - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return utf16leSlice(this, start, end) - - default: - if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) - encoding = (encoding + '').toLowerCase() - loweredCase = true - } - } -} - -// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect -// Buffer instances. -Buffer.prototype._isBuffer = true - -function swap (b, n, m) { - var i = b[n] - b[n] = b[m] - b[m] = i -} - -Buffer.prototype.swap16 = function swap16 () { - var len = this.length - if (len % 2 !== 0) { - throw new RangeError('Buffer size must be a multiple of 16-bits') - } - for (var i = 0; i < len; i += 2) { - swap(this, i, i + 1) - } - return this -} - -Buffer.prototype.swap32 = function swap32 () { - var len = this.length - if (len % 4 !== 0) { - throw new RangeError('Buffer size must be a multiple of 32-bits') - } - for (var i = 0; i < len; i += 4) { - swap(this, i, i + 3) - swap(this, i + 1, i + 2) - } - return this -} - -Buffer.prototype.swap64 = function swap64 () { - var len = this.length - if (len % 8 !== 0) { - throw new RangeError('Buffer size must be a multiple of 64-bits') - } - for (var i = 0; i < len; i += 8) { - swap(this, i, i + 7) - swap(this, i + 1, i + 6) - swap(this, i + 2, i + 5) - swap(this, i + 3, i + 4) - } - return this -} - -Buffer.prototype.toString = function toString () { - var length = this.length | 0 - if (length === 0) return '' - if (arguments.length === 0) return utf8Slice(this, 0, length) - return slowToString.apply(this, arguments) -} - -Buffer.prototype.equals = function equals (b) { - if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') - if (this === b) return true - return Buffer.compare(this, b) === 0 -} - -Buffer.prototype.inspect = function inspect () { - var str = '' - var max = exports.INSPECT_MAX_BYTES - if (this.length > 0) { - str = this.toString('hex', 0, max).match(/.{2}/g).join(' ') - if (this.length > max) str += ' ... ' - } - return '' -} - -Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { - if (!Buffer.isBuffer(target)) { - throw new TypeError('Argument must be a Buffer') - } - - if (start === undefined) { - start = 0 - } - if (end === undefined) { - end = target ? target.length : 0 - } - if (thisStart === undefined) { - thisStart = 0 - } - if (thisEnd === undefined) { - thisEnd = this.length - } - - if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { - throw new RangeError('out of range index') - } - - if (thisStart >= thisEnd && start >= end) { - return 0 - } - if (thisStart >= thisEnd) { - return -1 - } - if (start >= end) { - return 1 - } - - start >>>= 0 - end >>>= 0 - thisStart >>>= 0 - thisEnd >>>= 0 - - if (this === target) return 0 - - var x = thisEnd - thisStart - var y = end - start - var len = Math.min(x, y) - - var thisCopy = this.slice(thisStart, thisEnd) - var targetCopy = target.slice(start, end) - - for (var i = 0; i < len; ++i) { - if (thisCopy[i] !== targetCopy[i]) { - x = thisCopy[i] - y = targetCopy[i] - break - } - } - - if (x < y) return -1 - if (y < x) return 1 - return 0 -} - -// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, -// OR the last index of `val` in `buffer` at offset <= `byteOffset`. -// -// Arguments: -// - buffer - a Buffer to search -// - val - a string, Buffer, or number -// - byteOffset - an index into `buffer`; will be clamped to an int32 -// - encoding - an optional encoding, relevant is val is a string -// - dir - true for indexOf, false for lastIndexOf -function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { - // Empty buffer means no match - if (buffer.length === 0) return -1 - - // Normalize byteOffset - if (typeof byteOffset === 'string') { - encoding = byteOffset - byteOffset = 0 - } else if (byteOffset > 0x7fffffff) { - byteOffset = 0x7fffffff - } else if (byteOffset < -0x80000000) { - byteOffset = -0x80000000 - } - byteOffset = +byteOffset // Coerce to Number. - if (isNaN(byteOffset)) { - // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer - byteOffset = dir ? 0 : (buffer.length - 1) - } - - // Normalize byteOffset: negative offsets start from the end of the buffer - if (byteOffset < 0) byteOffset = buffer.length + byteOffset - if (byteOffset >= buffer.length) { - if (dir) return -1 - else byteOffset = buffer.length - 1 - } else if (byteOffset < 0) { - if (dir) byteOffset = 0 - else return -1 - } - - // Normalize val - if (typeof val === 'string') { - val = Buffer.from(val, encoding) - } - - // Finally, search either indexOf (if dir is true) or lastIndexOf - if (Buffer.isBuffer(val)) { - // Special case: looking for empty string/buffer always fails - if (val.length === 0) { - return -1 - } - return arrayIndexOf(buffer, val, byteOffset, encoding, dir) - } else if (typeof val === 'number') { - val = val & 0xFF // Search for a byte value [0-255] - if (Buffer.TYPED_ARRAY_SUPPORT && - typeof Uint8Array.prototype.indexOf === 'function') { - if (dir) { - return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) - } else { - return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) - } - } - return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir) - } - - throw new TypeError('val must be string, number or Buffer') -} - -function arrayIndexOf (arr, val, byteOffset, encoding, dir) { - var indexSize = 1 - var arrLength = arr.length - var valLength = val.length - - if (encoding !== undefined) { - encoding = String(encoding).toLowerCase() - if (encoding === 'ucs2' || encoding === 'ucs-2' || - encoding === 'utf16le' || encoding === 'utf-16le') { - if (arr.length < 2 || val.length < 2) { - return -1 - } - indexSize = 2 - arrLength /= 2 - valLength /= 2 - byteOffset /= 2 - } - } - - function read (buf, i) { - if (indexSize === 1) { - return buf[i] - } else { - return buf.readUInt16BE(i * indexSize) - } - } - - var i - if (dir) { - var foundIndex = -1 - for (i = byteOffset; i < arrLength; i++) { - if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { - if (foundIndex === -1) foundIndex = i - if (i - foundIndex + 1 === valLength) return foundIndex * indexSize - } else { - if (foundIndex !== -1) i -= i - foundIndex - foundIndex = -1 - } - } - } else { - if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength - for (i = byteOffset; i >= 0; i--) { - var found = true - for (var j = 0; j < valLength; j++) { - if (read(arr, i + j) !== read(val, j)) { - found = false - break - } - } - if (found) return i - } - } - - return -1 -} - -Buffer.prototype.includes = function includes (val, byteOffset, encoding) { - return this.indexOf(val, byteOffset, encoding) !== -1 -} - -Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { - return bidirectionalIndexOf(this, val, byteOffset, encoding, true) -} - -Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { - return bidirectionalIndexOf(this, val, byteOffset, encoding, false) -} - -function hexWrite (buf, string, offset, length) { - offset = Number(offset) || 0 - var remaining = buf.length - offset - if (!length) { - length = remaining - } else { - length = Number(length) - if (length > remaining) { - length = remaining - } - } - - // must be an even number of digits - var strLen = string.length - if (strLen % 2 !== 0) throw new TypeError('Invalid hex string') - - if (length > strLen / 2) { - length = strLen / 2 - } - for (var i = 0; i < length; ++i) { - var parsed = parseInt(string.substr(i * 2, 2), 16) - if (isNaN(parsed)) return i - buf[offset + i] = parsed - } - return i -} - -function utf8Write (buf, string, offset, length) { - return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) -} - -function asciiWrite (buf, string, offset, length) { - return blitBuffer(asciiToBytes(string), buf, offset, length) -} - -function latin1Write (buf, string, offset, length) { - return asciiWrite(buf, string, offset, length) -} - -function base64Write (buf, string, offset, length) { - return blitBuffer(base64ToBytes(string), buf, offset, length) -} - -function ucs2Write (buf, string, offset, length) { - return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) -} - -Buffer.prototype.write = function write (string, offset, length, encoding) { - // Buffer#write(string) - if (offset === undefined) { - encoding = 'utf8' - length = this.length - offset = 0 - // Buffer#write(string, encoding) - } else if (length === undefined && typeof offset === 'string') { - encoding = offset - length = this.length - offset = 0 - // Buffer#write(string, offset[, length][, encoding]) - } else if (isFinite(offset)) { - offset = offset | 0 - if (isFinite(length)) { - length = length | 0 - if (encoding === undefined) encoding = 'utf8' - } else { - encoding = length - length = undefined - } - // legacy write(string, encoding, offset, length) - remove in v0.13 - } else { - throw new Error( - 'Buffer.write(string, encoding, offset[, length]) is no longer supported' - ) - } - - var remaining = this.length - offset - if (length === undefined || length > remaining) length = remaining - - if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { - throw new RangeError('Attempt to write outside buffer bounds') - } - - if (!encoding) encoding = 'utf8' - - var loweredCase = false - for (;;) { - switch (encoding) { - case 'hex': - return hexWrite(this, string, offset, length) - - case 'utf8': - case 'utf-8': - return utf8Write(this, string, offset, length) - - case 'ascii': - return asciiWrite(this, string, offset, length) - - case 'latin1': - case 'binary': - return latin1Write(this, string, offset, length) - - case 'base64': - // Warning: maxLength not taken into account in base64Write - return base64Write(this, string, offset, length) - - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return ucs2Write(this, string, offset, length) - - default: - if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) - encoding = ('' + encoding).toLowerCase() - loweredCase = true - } - } -} - -Buffer.prototype.toJSON = function toJSON () { - return { - type: 'Buffer', - data: Array.prototype.slice.call(this._arr || this, 0) - } -} - -function base64Slice (buf, start, end) { - if (start === 0 && end === buf.length) { - return base64.fromByteArray(buf) - } else { - return base64.fromByteArray(buf.slice(start, end)) - } -} - -function utf8Slice (buf, start, end) { - end = Math.min(buf.length, end) - var res = [] - - var i = start - while (i < end) { - var firstByte = buf[i] - var codePoint = null - var bytesPerSequence = (firstByte > 0xEF) ? 4 - : (firstByte > 0xDF) ? 3 - : (firstByte > 0xBF) ? 2 - : 1 - - if (i + bytesPerSequence <= end) { - var secondByte, thirdByte, fourthByte, tempCodePoint - - switch (bytesPerSequence) { - case 1: - if (firstByte < 0x80) { - codePoint = firstByte - } - break - case 2: - secondByte = buf[i + 1] - if ((secondByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) - if (tempCodePoint > 0x7F) { - codePoint = tempCodePoint - } - } - break - case 3: - secondByte = buf[i + 1] - thirdByte = buf[i + 2] - if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) - if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { - codePoint = tempCodePoint - } - } - break - case 4: - secondByte = buf[i + 1] - thirdByte = buf[i + 2] - fourthByte = buf[i + 3] - if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) - if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { - codePoint = tempCodePoint - } - } - } - } - - if (codePoint === null) { - // we did not generate a valid codePoint so insert a - // replacement char (U+FFFD) and advance only 1 byte - codePoint = 0xFFFD - bytesPerSequence = 1 - } else if (codePoint > 0xFFFF) { - // encode to utf16 (surrogate pair dance) - codePoint -= 0x10000 - res.push(codePoint >>> 10 & 0x3FF | 0xD800) - codePoint = 0xDC00 | codePoint & 0x3FF - } - - res.push(codePoint) - i += bytesPerSequence - } - - return decodeCodePointsArray(res) -} - -// Based on http://stackoverflow.com/a/22747272/680742, the browser with -// the lowest limit is Chrome, with 0x10000 args. -// We go 1 magnitude less, for safety -var MAX_ARGUMENTS_LENGTH = 0x1000 - -function decodeCodePointsArray (codePoints) { - var len = codePoints.length - if (len <= MAX_ARGUMENTS_LENGTH) { - return String.fromCharCode.apply(String, codePoints) // avoid extra slice() - } - - // Decode in chunks to avoid "call stack size exceeded". - var res = '' - var i = 0 - while (i < len) { - res += String.fromCharCode.apply( - String, - codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) - ) - } - return res -} - -function asciiSlice (buf, start, end) { - var ret = '' - end = Math.min(buf.length, end) - - for (var i = start; i < end; ++i) { - ret += String.fromCharCode(buf[i] & 0x7F) - } - return ret -} - -function latin1Slice (buf, start, end) { - var ret = '' - end = Math.min(buf.length, end) - - for (var i = start; i < end; ++i) { - ret += String.fromCharCode(buf[i]) - } - return ret -} - -function hexSlice (buf, start, end) { - var len = buf.length - - if (!start || start < 0) start = 0 - if (!end || end < 0 || end > len) end = len - - var out = '' - for (var i = start; i < end; ++i) { - out += toHex(buf[i]) - } - return out -} - -function utf16leSlice (buf, start, end) { - var bytes = buf.slice(start, end) - var res = '' - for (var i = 0; i < bytes.length; i += 2) { - res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256) - } - return res -} - -Buffer.prototype.slice = function slice (start, end) { - var len = this.length - start = ~~start - end = end === undefined ? len : ~~end - - if (start < 0) { - start += len - if (start < 0) start = 0 - } else if (start > len) { - start = len - } - - if (end < 0) { - end += len - if (end < 0) end = 0 - } else if (end > len) { - end = len - } - - if (end < start) end = start - - var newBuf - if (Buffer.TYPED_ARRAY_SUPPORT) { - newBuf = this.subarray(start, end) - newBuf.__proto__ = Buffer.prototype - } else { - var sliceLen = end - start - newBuf = new Buffer(sliceLen, undefined) - for (var i = 0; i < sliceLen; ++i) { - newBuf[i] = this[i + start] - } - } - - return newBuf -} - -/* - * Need to make sure that buffer isn't trying to write out of bounds. - */ -function checkOffset (offset, ext, length) { - if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') - if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') -} - -Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) - - var val = this[offset] - var mul = 1 - var i = 0 - while (++i < byteLength && (mul *= 0x100)) { - val += this[offset + i] * mul - } - - return val -} - -Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - checkOffset(offset, byteLength, this.length) - } - - var val = this[offset + --byteLength] - var mul = 1 - while (byteLength > 0 && (mul *= 0x100)) { - val += this[offset + --byteLength] * mul - } - - return val -} - -Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { - if (!noAssert) checkOffset(offset, 1, this.length) - return this[offset] -} - -Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - return this[offset] | (this[offset + 1] << 8) -} - -Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - return (this[offset] << 8) | this[offset + 1] -} - -Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - - return ((this[offset]) | - (this[offset + 1] << 8) | - (this[offset + 2] << 16)) + - (this[offset + 3] * 0x1000000) -} - -Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - - return (this[offset] * 0x1000000) + - ((this[offset + 1] << 16) | - (this[offset + 2] << 8) | - this[offset + 3]) -} - -Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) - - var val = this[offset] - var mul = 1 - var i = 0 - while (++i < byteLength && (mul *= 0x100)) { - val += this[offset + i] * mul - } - mul *= 0x80 - - if (val >= mul) val -= Math.pow(2, 8 * byteLength) - - return val -} - -Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) - - var i = byteLength - var mul = 1 - var val = this[offset + --i] - while (i > 0 && (mul *= 0x100)) { - val += this[offset + --i] * mul - } - mul *= 0x80 - - if (val >= mul) val -= Math.pow(2, 8 * byteLength) - - return val -} - -Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { - if (!noAssert) checkOffset(offset, 1, this.length) - if (!(this[offset] & 0x80)) return (this[offset]) - return ((0xff - this[offset] + 1) * -1) -} - -Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - var val = this[offset] | (this[offset + 1] << 8) - return (val & 0x8000) ? val | 0xFFFF0000 : val -} - -Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - var val = this[offset + 1] | (this[offset] << 8) - return (val & 0x8000) ? val | 0xFFFF0000 : val -} - -Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - - return (this[offset]) | - (this[offset + 1] << 8) | - (this[offset + 2] << 16) | - (this[offset + 3] << 24) -} - -Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - - return (this[offset] << 24) | - (this[offset + 1] << 16) | - (this[offset + 2] << 8) | - (this[offset + 3]) -} - -Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - return ieee754.read(this, offset, true, 23, 4) -} - -Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - return ieee754.read(this, offset, false, 23, 4) -} - -Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 8, this.length) - return ieee754.read(this, offset, true, 52, 8) -} - -Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 8, this.length) - return ieee754.read(this, offset, false, 52, 8) -} - -function checkInt (buf, value, offset, ext, max, min) { - if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance') - if (value > max || value < min) throw new RangeError('"value" argument is out of bounds') - if (offset + ext > buf.length) throw new RangeError('Index out of range') -} - -Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - var maxBytes = Math.pow(2, 8 * byteLength) - 1 - checkInt(this, value, offset, byteLength, maxBytes, 0) - } - - var mul = 1 - var i = 0 - this[offset] = value & 0xFF - while (++i < byteLength && (mul *= 0x100)) { - this[offset + i] = (value / mul) & 0xFF - } - - return offset + byteLength -} - -Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - var maxBytes = Math.pow(2, 8 * byteLength) - 1 - checkInt(this, value, offset, byteLength, maxBytes, 0) - } - - var i = byteLength - 1 - var mul = 1 - this[offset + i] = value & 0xFF - while (--i >= 0 && (mul *= 0x100)) { - this[offset + i] = (value / mul) & 0xFF - } - - return offset + byteLength -} - -Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) - if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) - this[offset] = (value & 0xff) - return offset + 1 -} - -function objectWriteUInt16 (buf, value, offset, littleEndian) { - if (value < 0) value = 0xffff + value + 1 - for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) { - buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> - (littleEndian ? i : 1 - i) * 8 - } -} - -Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - } else { - objectWriteUInt16(this, value, offset, true) - } - return offset + 2 -} - -Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - } else { - objectWriteUInt16(this, value, offset, false) - } - return offset + 2 -} - -function objectWriteUInt32 (buf, value, offset, littleEndian) { - if (value < 0) value = 0xffffffff + value + 1 - for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) { - buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff - } -} - -Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset + 3] = (value >>> 24) - this[offset + 2] = (value >>> 16) - this[offset + 1] = (value >>> 8) - this[offset] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, true) - } - return offset + 4 -} - -Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, false) - } - return offset + 4 -} - -Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - var limit = Math.pow(2, 8 * byteLength - 1) - - checkInt(this, value, offset, byteLength, limit - 1, -limit) - } - - var i = 0 - var mul = 1 - var sub = 0 - this[offset] = value & 0xFF - while (++i < byteLength && (mul *= 0x100)) { - if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { - sub = 1 - } - this[offset + i] = ((value / mul) >> 0) - sub & 0xFF - } - - return offset + byteLength -} - -Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - var limit = Math.pow(2, 8 * byteLength - 1) - - checkInt(this, value, offset, byteLength, limit - 1, -limit) - } - - var i = byteLength - 1 - var mul = 1 - var sub = 0 - this[offset + i] = value & 0xFF - while (--i >= 0 && (mul *= 0x100)) { - if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { - sub = 1 - } - this[offset + i] = ((value / mul) >> 0) - sub & 0xFF - } - - return offset + byteLength -} - -Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) - if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) - if (value < 0) value = 0xff + value + 1 - this[offset] = (value & 0xff) - return offset + 1 -} - -Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - } else { - objectWriteUInt16(this, value, offset, true) - } - return offset + 2 -} - -Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - } else { - objectWriteUInt16(this, value, offset, false) - } - return offset + 2 -} - -Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - this[offset + 2] = (value >>> 16) - this[offset + 3] = (value >>> 24) - } else { - objectWriteUInt32(this, value, offset, true) - } - return offset + 4 -} - -Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) - if (value < 0) value = 0xffffffff + value + 1 - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, false) - } - return offset + 4 -} - -function checkIEEE754 (buf, value, offset, ext, max, min) { - if (offset + ext > buf.length) throw new RangeError('Index out of range') - if (offset < 0) throw new RangeError('Index out of range') -} - -function writeFloat (buf, value, offset, littleEndian, noAssert) { - if (!noAssert) { - checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) - } - ieee754.write(buf, value, offset, littleEndian, 23, 4) - return offset + 4 -} - -Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { - return writeFloat(this, value, offset, true, noAssert) -} - -Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { - return writeFloat(this, value, offset, false, noAssert) -} - -function writeDouble (buf, value, offset, littleEndian, noAssert) { - if (!noAssert) { - checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) - } - ieee754.write(buf, value, offset, littleEndian, 52, 8) - return offset + 8 -} - -Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { - return writeDouble(this, value, offset, true, noAssert) -} - -Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { - return writeDouble(this, value, offset, false, noAssert) -} - -// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) -Buffer.prototype.copy = function copy (target, targetStart, start, end) { - if (!start) start = 0 - if (!end && end !== 0) end = this.length - if (targetStart >= target.length) targetStart = target.length - if (!targetStart) targetStart = 0 - if (end > 0 && end < start) end = start - - // Copy 0 bytes; we're done - if (end === start) return 0 - if (target.length === 0 || this.length === 0) return 0 - - // Fatal error conditions - if (targetStart < 0) { - throw new RangeError('targetStart out of bounds') - } - if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds') - if (end < 0) throw new RangeError('sourceEnd out of bounds') - - // Are we oob? - if (end > this.length) end = this.length - if (target.length - targetStart < end - start) { - end = target.length - targetStart + start - } - - var len = end - start - var i - - if (this === target && start < targetStart && targetStart < end) { - // descending copy from end - for (i = len - 1; i >= 0; --i) { - target[i + targetStart] = this[i + start] - } - } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { - // ascending copy from start - for (i = 0; i < len; ++i) { - target[i + targetStart] = this[i + start] - } - } else { - Uint8Array.prototype.set.call( - target, - this.subarray(start, start + len), - targetStart - ) - } - - return len -} - -// Usage: -// buffer.fill(number[, offset[, end]]) -// buffer.fill(buffer[, offset[, end]]) -// buffer.fill(string[, offset[, end]][, encoding]) -Buffer.prototype.fill = function fill (val, start, end, encoding) { - // Handle string cases: - if (typeof val === 'string') { - if (typeof start === 'string') { - encoding = start - start = 0 - end = this.length - } else if (typeof end === 'string') { - encoding = end - end = this.length - } - if (val.length === 1) { - var code = val.charCodeAt(0) - if (code < 256) { - val = code - } - } - if (encoding !== undefined && typeof encoding !== 'string') { - throw new TypeError('encoding must be a string') - } - if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { - throw new TypeError('Unknown encoding: ' + encoding) - } - } else if (typeof val === 'number') { - val = val & 255 - } - - // Invalid ranges are not set to a default, so can range check early. - if (start < 0 || this.length < start || this.length < end) { - throw new RangeError('Out of range index') - } - - if (end <= start) { - return this - } - - start = start >>> 0 - end = end === undefined ? this.length : end >>> 0 - - if (!val) val = 0 - - var i - if (typeof val === 'number') { - for (i = start; i < end; ++i) { - this[i] = val - } - } else { - var bytes = Buffer.isBuffer(val) - ? val - : utf8ToBytes(new Buffer(val, encoding).toString()) - var len = bytes.length - for (i = 0; i < end - start; ++i) { - this[i + start] = bytes[i % len] - } - } - - return this -} - -// HELPER FUNCTIONS -// ================ - -var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g - -function base64clean (str) { - // Node strips out invalid characters like \n and \t from the string, base64-js does not - str = stringtrim(str).replace(INVALID_BASE64_RE, '') - // Node converts strings with length < 2 to '' - if (str.length < 2) return '' - // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not - while (str.length % 4 !== 0) { - str = str + '=' - } - return str -} - -function stringtrim (str) { - if (str.trim) return str.trim() - return str.replace(/^\s+|\s+$/g, '') -} - -function toHex (n) { - if (n < 16) return '0' + n.toString(16) - return n.toString(16) -} - -function utf8ToBytes (string, units) { - units = units || Infinity - var codePoint - var length = string.length - var leadSurrogate = null - var bytes = [] - - for (var i = 0; i < length; ++i) { - codePoint = string.charCodeAt(i) - - // is surrogate component - if (codePoint > 0xD7FF && codePoint < 0xE000) { - // last char was a lead - if (!leadSurrogate) { - // no lead yet - if (codePoint > 0xDBFF) { - // unexpected trail - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - continue - } else if (i + 1 === length) { - // unpaired lead - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - continue - } - - // valid lead - leadSurrogate = codePoint - - continue - } - - // 2 leads in a row - if (codePoint < 0xDC00) { - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - leadSurrogate = codePoint - continue - } - - // valid surrogate pair - codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 - } else if (leadSurrogate) { - // valid bmp char, but last char was a lead - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - } - - leadSurrogate = null - - // encode utf8 - if (codePoint < 0x80) { - if ((units -= 1) < 0) break - bytes.push(codePoint) - } else if (codePoint < 0x800) { - if ((units -= 2) < 0) break - bytes.push( - codePoint >> 0x6 | 0xC0, - codePoint & 0x3F | 0x80 - ) - } else if (codePoint < 0x10000) { - if ((units -= 3) < 0) break - bytes.push( - codePoint >> 0xC | 0xE0, - codePoint >> 0x6 & 0x3F | 0x80, - codePoint & 0x3F | 0x80 - ) - } else if (codePoint < 0x110000) { - if ((units -= 4) < 0) break - bytes.push( - codePoint >> 0x12 | 0xF0, - codePoint >> 0xC & 0x3F | 0x80, - codePoint >> 0x6 & 0x3F | 0x80, - codePoint & 0x3F | 0x80 - ) - } else { - throw new Error('Invalid code point') - } - } - - return bytes -} - -function asciiToBytes (str) { - var byteArray = [] - for (var i = 0; i < str.length; ++i) { - // Node's code seems to be doing this and not & 0x7F.. - byteArray.push(str.charCodeAt(i) & 0xFF) - } - return byteArray -} - -function utf16leToBytes (str, units) { - var c, hi, lo - var byteArray = [] - for (var i = 0; i < str.length; ++i) { - if ((units -= 2) < 0) break - - c = str.charCodeAt(i) - hi = c >> 8 - lo = c % 256 - byteArray.push(lo) - byteArray.push(hi) - } - - return byteArray -} - -function base64ToBytes (str) { - return base64.toByteArray(base64clean(str)) -} - -function blitBuffer (src, dst, offset, length) { - for (var i = 0; i < length; ++i) { - if ((i + offset >= dst.length) || (i >= src.length)) break - dst[i + offset] = src[i] - } - return i -} - -function isnan (val) { - return val !== val // eslint-disable-line no-self-compare -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(88))) - -/***/ }), -/* 127 */ -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__(136); -module.exports = __webpack_require__(24).RegExp.escape; - -/***/ }), -/* 128 */ -/***/ (function(module, exports, __webpack_require__) { - -var isObject = __webpack_require__(4) - , isArray = __webpack_require__(70) - , SPECIES = __webpack_require__(5)('species'); - -module.exports = function(original){ - var C; - if(isArray(original)){ - C = original.constructor; - // cross-realm fallback - if(typeof C == 'function' && (C === Array || isArray(C.prototype)))C = undefined; - if(isObject(C)){ - C = C[SPECIES]; - if(C === null)C = undefined; - } - } return C === undefined ? Array : C; -}; - -/***/ }), -/* 129 */ -/***/ (function(module, exports, __webpack_require__) { - -// 9.4.2.3 ArraySpeciesCreate(originalArray, length) -var speciesConstructor = __webpack_require__(128); - -module.exports = function(original, length){ - return new (speciesConstructor(original))(length); -}; - -/***/ }), -/* 130 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var anObject = __webpack_require__(1) - , toPrimitive = __webpack_require__(23) - , NUMBER = 'number'; - -module.exports = function(hint){ - if(hint !== 'string' && hint !== NUMBER && hint !== 'default')throw TypeError('Incorrect hint'); - return toPrimitive(anObject(this), hint != NUMBER); -}; - -/***/ }), -/* 131 */ -/***/ (function(module, exports, __webpack_require__) { - -// all enumerable object keys, includes symbols -var getKeys = __webpack_require__(36) - , gOPS = __webpack_require__(59) - , pIE = __webpack_require__(50); -module.exports = function(it){ - var result = getKeys(it) - , getSymbols = gOPS.f; - if(getSymbols){ - var symbols = getSymbols(it) - , isEnum = pIE.f - , i = 0 - , key; - while(symbols.length > i)if(isEnum.call(it, key = symbols[i++]))result.push(key); - } return result; -}; - -/***/ }), -/* 132 */ -/***/ (function(module, exports, __webpack_require__) { - -var getKeys = __webpack_require__(36) - , toIObject = __webpack_require__(15); -module.exports = function(object, el){ - var O = toIObject(object) - , keys = getKeys(O) - , length = keys.length - , index = 0 - , key; - while(length > index)if(O[key = keys[index++]] === el)return key; -}; - -/***/ }), -/* 133 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var path = __webpack_require__(134) - , invoke = __webpack_require__(55) - , aFunction = __webpack_require__(11); -module.exports = function(/* ...pargs */){ - var fn = aFunction(this) - , length = arguments.length - , pargs = Array(length) - , i = 0 - , _ = path._ - , holder = false; - while(length > i)if((pargs[i] = arguments[i++]) === _)holder = true; - return function(/* ...args */){ - var that = this - , aLen = arguments.length - , j = 0, k = 0, args; - if(!holder && !aLen)return invoke(fn, pargs, that); - args = pargs.slice(); - if(holder)for(;length > j; j++)if(args[j] === _)args[j] = arguments[k++]; - while(aLen > k)args.push(arguments[k++]); - return invoke(fn, args, that); - }; -}; - -/***/ }), -/* 134 */ -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__(2); - -/***/ }), -/* 135 */ -/***/ (function(module, exports) { - -module.exports = function(regExp, replace){ - var replacer = replace === Object(replace) ? function(part){ - return replace[part]; - } : replace; - return function(it){ - return String(it).replace(regExp, replacer); - }; -}; - -/***/ }), -/* 136 */ -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/benjamingr/RexExp.escape -var $export = __webpack_require__(0) - , $re = __webpack_require__(135)(/[\\^$*+?.()|[\]{}]/g, '\\$&'); - -$export($export.S, 'RegExp', {escape: function escape(it){ return $re(it); }}); - - -/***/ }), -/* 137 */ -/***/ (function(module, exports, __webpack_require__) { - -// 22.1.3.3 Array.prototype.copyWithin(target, start, end = this.length) -var $export = __webpack_require__(0); - -$export($export.P, 'Array', {copyWithin: __webpack_require__(90)}); - -__webpack_require__(42)('copyWithin'); - -/***/ }), -/* 138 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , $every = __webpack_require__(21)(4); - -$export($export.P + $export.F * !__webpack_require__(20)([].every, true), 'Array', { - // 22.1.3.5 / 15.4.4.16 Array.prototype.every(callbackfn [, thisArg]) - every: function every(callbackfn /* , thisArg */){ - return $every(this, callbackfn, arguments[1]); - } -}); - -/***/ }), -/* 139 */ -/***/ (function(module, exports, __webpack_require__) { - -// 22.1.3.6 Array.prototype.fill(value, start = 0, end = this.length) -var $export = __webpack_require__(0); - -$export($export.P, 'Array', {fill: __webpack_require__(62)}); - -__webpack_require__(42)('fill'); - -/***/ }), -/* 140 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , $filter = __webpack_require__(21)(2); - -$export($export.P + $export.F * !__webpack_require__(20)([].filter, true), 'Array', { - // 22.1.3.7 / 15.4.4.20 Array.prototype.filter(callbackfn [, thisArg]) - filter: function filter(callbackfn /* , thisArg */){ - return $filter(this, callbackfn, arguments[1]); - } -}); - -/***/ }), -/* 141 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// 22.1.3.9 Array.prototype.findIndex(predicate, thisArg = undefined) -var $export = __webpack_require__(0) - , $find = __webpack_require__(21)(6) - , KEY = 'findIndex' - , forced = true; -// Shouldn't skip holes -if(KEY in [])Array(1)[KEY](function(){ forced = false; }); -$export($export.P + $export.F * forced, 'Array', { - findIndex: function findIndex(callbackfn/*, that = undefined */){ - return $find(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined); - } -}); -__webpack_require__(42)(KEY); - -/***/ }), -/* 142 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// 22.1.3.8 Array.prototype.find(predicate, thisArg = undefined) -var $export = __webpack_require__(0) - , $find = __webpack_require__(21)(5) - , KEY = 'find' - , forced = true; -// Shouldn't skip holes -if(KEY in [])Array(1)[KEY](function(){ forced = false; }); -$export($export.P + $export.F * forced, 'Array', { - find: function find(callbackfn/*, that = undefined */){ - return $find(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined); - } -}); -__webpack_require__(42)(KEY); - -/***/ }), -/* 143 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , $forEach = __webpack_require__(21)(0) - , STRICT = __webpack_require__(20)([].forEach, true); - -$export($export.P + $export.F * !STRICT, 'Array', { - // 22.1.3.10 / 15.4.4.18 Array.prototype.forEach(callbackfn [, thisArg]) - forEach: function forEach(callbackfn /* , thisArg */){ - return $forEach(this, callbackfn, arguments[1]); - } -}); - -/***/ }), -/* 144 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var ctx = __webpack_require__(25) - , $export = __webpack_require__(0) - , toObject = __webpack_require__(9) - , call = __webpack_require__(99) - , isArrayIter = __webpack_require__(69) - , toLength = __webpack_require__(8) - , createProperty = __webpack_require__(63) - , getIterFn = __webpack_require__(86); - -$export($export.S + $export.F * !__webpack_require__(57)(function(iter){ Array.from(iter); }), 'Array', { - // 22.1.2.1 Array.from(arrayLike, mapfn = undefined, thisArg = undefined) - from: function from(arrayLike/*, mapfn = undefined, thisArg = undefined*/){ - var O = toObject(arrayLike) - , C = typeof this == 'function' ? this : Array - , aLen = arguments.length - , mapfn = aLen > 1 ? arguments[1] : undefined - , mapping = mapfn !== undefined - , index = 0 - , iterFn = getIterFn(O) - , length, result, step, iterator; - if(mapping)mapfn = ctx(mapfn, aLen > 2 ? arguments[2] : undefined, 2); - // if object isn't iterable or it's array with default iterator - use simple case - if(iterFn != undefined && !(C == Array && isArrayIter(iterFn))){ - for(iterator = iterFn.call(O), result = new C; !(step = iterator.next()).done; index++){ - createProperty(result, index, mapping ? call(iterator, mapfn, [step.value, index], true) : step.value); - } - } else { - length = toLength(O.length); - for(result = new C(length); length > index; index++){ - createProperty(result, index, mapping ? mapfn(O[index], index) : O[index]); - } - } - result.length = index; - return result; - } -}); - - -/***/ }), -/* 145 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , $indexOf = __webpack_require__(51)(false) - , $native = [].indexOf - , NEGATIVE_ZERO = !!$native && 1 / [1].indexOf(1, -0) < 0; - -$export($export.P + $export.F * (NEGATIVE_ZERO || !__webpack_require__(20)($native)), 'Array', { - // 22.1.3.11 / 15.4.4.14 Array.prototype.indexOf(searchElement [, fromIndex]) - indexOf: function indexOf(searchElement /*, fromIndex = 0 */){ - return NEGATIVE_ZERO - // convert -0 to +0 - ? $native.apply(this, arguments) || 0 - : $indexOf(this, searchElement, arguments[1]); - } -}); - -/***/ }), -/* 146 */ -/***/ (function(module, exports, __webpack_require__) { - -// 22.1.2.2 / 15.4.3.2 Array.isArray(arg) -var $export = __webpack_require__(0); - -$export($export.S, 'Array', {isArray: __webpack_require__(70)}); - -/***/ }), -/* 147 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// 22.1.3.13 Array.prototype.join(separator) -var $export = __webpack_require__(0) - , toIObject = __webpack_require__(15) - , arrayJoin = [].join; - -// fallback for not array-like strings -$export($export.P + $export.F * (__webpack_require__(49) != Object || !__webpack_require__(20)(arrayJoin)), 'Array', { - join: function join(separator){ - return arrayJoin.call(toIObject(this), separator === undefined ? ',' : separator); - } -}); - -/***/ }), -/* 148 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , toIObject = __webpack_require__(15) - , toInteger = __webpack_require__(31) - , toLength = __webpack_require__(8) - , $native = [].lastIndexOf - , NEGATIVE_ZERO = !!$native && 1 / [1].lastIndexOf(1, -0) < 0; - -$export($export.P + $export.F * (NEGATIVE_ZERO || !__webpack_require__(20)($native)), 'Array', { - // 22.1.3.14 / 15.4.4.15 Array.prototype.lastIndexOf(searchElement [, fromIndex]) - lastIndexOf: function lastIndexOf(searchElement /*, fromIndex = @[*-1] */){ - // convert -0 to +0 - if(NEGATIVE_ZERO)return $native.apply(this, arguments) || 0; - var O = toIObject(this) - , length = toLength(O.length) - , index = length - 1; - if(arguments.length > 1)index = Math.min(index, toInteger(arguments[1])); - if(index < 0)index = length + index; - for(;index >= 0; index--)if(index in O)if(O[index] === searchElement)return index || 0; - return -1; - } -}); - -/***/ }), -/* 149 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , $map = __webpack_require__(21)(1); - -$export($export.P + $export.F * !__webpack_require__(20)([].map, true), 'Array', { - // 22.1.3.15 / 15.4.4.19 Array.prototype.map(callbackfn [, thisArg]) - map: function map(callbackfn /* , thisArg */){ - return $map(this, callbackfn, arguments[1]); - } -}); - -/***/ }), -/* 150 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , createProperty = __webpack_require__(63); - -// WebKit Array.of isn't generic -$export($export.S + $export.F * __webpack_require__(3)(function(){ - function F(){} - return !(Array.of.call(F) instanceof F); -}), 'Array', { - // 22.1.2.3 Array.of( ...items) - of: function of(/* ...args */){ - var index = 0 - , aLen = arguments.length - , result = new (typeof this == 'function' ? this : Array)(aLen); - while(aLen > index)createProperty(result, index, arguments[index++]); - result.length = aLen; - return result; - } -}); - -/***/ }), -/* 151 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , $reduce = __webpack_require__(92); - -$export($export.P + $export.F * !__webpack_require__(20)([].reduceRight, true), 'Array', { - // 22.1.3.19 / 15.4.4.22 Array.prototype.reduceRight(callbackfn [, initialValue]) - reduceRight: function reduceRight(callbackfn /* , initialValue */){ - return $reduce(this, callbackfn, arguments.length, arguments[1], true); - } -}); - -/***/ }), -/* 152 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , $reduce = __webpack_require__(92); - -$export($export.P + $export.F * !__webpack_require__(20)([].reduce, true), 'Array', { - // 22.1.3.18 / 15.4.4.21 Array.prototype.reduce(callbackfn [, initialValue]) - reduce: function reduce(callbackfn /* , initialValue */){ - return $reduce(this, callbackfn, arguments.length, arguments[1], false); - } -}); - -/***/ }), -/* 153 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , html = __webpack_require__(67) - , cof = __webpack_require__(18) - , toIndex = __webpack_require__(39) - , toLength = __webpack_require__(8) - , arraySlice = [].slice; - -// fallback for not array-like ES3 strings and DOM objects -$export($export.P + $export.F * __webpack_require__(3)(function(){ - if(html)arraySlice.call(html); -}), 'Array', { - slice: function slice(begin, end){ - var len = toLength(this.length) - , klass = cof(this); - end = end === undefined ? len : end; - if(klass == 'Array')return arraySlice.call(this, begin, end); - var start = toIndex(begin, len) - , upTo = toIndex(end, len) - , size = toLength(upTo - start) - , cloned = Array(size) - , i = 0; - for(; i < size; i++)cloned[i] = klass == 'String' - ? this.charAt(start + i) - : this[start + i]; - return cloned; - } -}); - -/***/ }), -/* 154 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , $some = __webpack_require__(21)(3); - -$export($export.P + $export.F * !__webpack_require__(20)([].some, true), 'Array', { - // 22.1.3.23 / 15.4.4.17 Array.prototype.some(callbackfn [, thisArg]) - some: function some(callbackfn /* , thisArg */){ - return $some(this, callbackfn, arguments[1]); - } -}); - -/***/ }), -/* 155 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , aFunction = __webpack_require__(11) - , toObject = __webpack_require__(9) - , fails = __webpack_require__(3) - , $sort = [].sort - , test = [1, 2, 3]; - -$export($export.P + $export.F * (fails(function(){ - // IE8- - test.sort(undefined); -}) || !fails(function(){ - // V8 bug - test.sort(null); - // Old WebKit -}) || !__webpack_require__(20)($sort)), 'Array', { - // 22.1.3.25 Array.prototype.sort(comparefn) - sort: function sort(comparefn){ - return comparefn === undefined - ? $sort.call(toObject(this)) - : $sort.call(toObject(this), aFunction(comparefn)); - } -}); - -/***/ }), -/* 156 */ -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__(38)('Array'); - -/***/ }), -/* 157 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.3.3.1 / 15.9.4.4 Date.now() -var $export = __webpack_require__(0); - -$export($export.S, 'Date', {now: function(){ return new Date().getTime(); }}); - -/***/ }), -/* 158 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// 20.3.4.36 / 15.9.5.43 Date.prototype.toISOString() -var $export = __webpack_require__(0) - , fails = __webpack_require__(3) - , getTime = Date.prototype.getTime; - -var lz = function(num){ - return num > 9 ? num : '0' + num; -}; - -// PhantomJS / old WebKit has a broken implementations -$export($export.P + $export.F * (fails(function(){ - return new Date(-5e13 - 1).toISOString() != '0385-07-25T07:06:39.999Z'; -}) || !fails(function(){ - new Date(NaN).toISOString(); -})), 'Date', { - toISOString: function toISOString(){ - if(!isFinite(getTime.call(this)))throw RangeError('Invalid time value'); - var d = this - , y = d.getUTCFullYear() - , m = d.getUTCMilliseconds() - , s = y < 0 ? '-' : y > 9999 ? '+' : ''; - return s + ('00000' + Math.abs(y)).slice(s ? -6 : -4) + - '-' + lz(d.getUTCMonth() + 1) + '-' + lz(d.getUTCDate()) + - 'T' + lz(d.getUTCHours()) + ':' + lz(d.getUTCMinutes()) + - ':' + lz(d.getUTCSeconds()) + '.' + (m > 99 ? m : '0' + lz(m)) + 'Z'; - } -}); - -/***/ }), -/* 159 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , toObject = __webpack_require__(9) - , toPrimitive = __webpack_require__(23); - -$export($export.P + $export.F * __webpack_require__(3)(function(){ - return new Date(NaN).toJSON() !== null || Date.prototype.toJSON.call({toISOString: function(){ return 1; }}) !== 1; -}), 'Date', { - toJSON: function toJSON(key){ - var O = toObject(this) - , pv = toPrimitive(O); - return typeof pv == 'number' && !isFinite(pv) ? null : O.toISOString(); - } -}); - -/***/ }), -/* 160 */ -/***/ (function(module, exports, __webpack_require__) { - -var TO_PRIMITIVE = __webpack_require__(5)('toPrimitive') - , proto = Date.prototype; - -if(!(TO_PRIMITIVE in proto))__webpack_require__(12)(proto, TO_PRIMITIVE, __webpack_require__(130)); - -/***/ }), -/* 161 */ -/***/ (function(module, exports, __webpack_require__) { - -var DateProto = Date.prototype - , INVALID_DATE = 'Invalid Date' - , TO_STRING = 'toString' - , $toString = DateProto[TO_STRING] - , getTime = DateProto.getTime; -if(new Date(NaN) + '' != INVALID_DATE){ - __webpack_require__(13)(DateProto, TO_STRING, function toString(){ - var value = getTime.call(this); - return value === value ? $toString.call(this) : INVALID_DATE; - }); -} - -/***/ }), -/* 162 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.2.3.2 / 15.3.4.5 Function.prototype.bind(thisArg, args...) -var $export = __webpack_require__(0); - -$export($export.P, 'Function', {bind: __webpack_require__(93)}); - -/***/ }), -/* 163 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var isObject = __webpack_require__(4) - , getPrototypeOf = __webpack_require__(17) - , HAS_INSTANCE = __webpack_require__(5)('hasInstance') - , FunctionProto = Function.prototype; -// 19.2.3.6 Function.prototype[@@hasInstance](V) -if(!(HAS_INSTANCE in FunctionProto))__webpack_require__(7).f(FunctionProto, HAS_INSTANCE, {value: function(O){ - if(typeof this != 'function' || !isObject(O))return false; - if(!isObject(this.prototype))return O instanceof this; - // for environment w/o native `@@hasInstance` logic enough `instanceof`, but add this: - while(O = getPrototypeOf(O))if(this.prototype === O)return true; - return false; -}}); - -/***/ }), -/* 164 */ -/***/ (function(module, exports, __webpack_require__) { - -var dP = __webpack_require__(7).f - , createDesc = __webpack_require__(30) - , has = __webpack_require__(10) - , FProto = Function.prototype - , nameRE = /^\s*function ([^ (]*)/ - , NAME = 'name'; - -var isExtensible = Object.isExtensible || function(){ - return true; -}; - -// 19.2.4.2 name -NAME in FProto || __webpack_require__(6) && dP(FProto, NAME, { - configurable: true, - get: function(){ - try { - var that = this - , name = ('' + that).match(nameRE)[1]; - has(that, NAME) || !isExtensible(that) || dP(that, NAME, createDesc(5, name)); - return name; - } catch(e){ - return ''; - } - } -}); - -/***/ }), -/* 165 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.2.2.3 Math.acosh(x) -var $export = __webpack_require__(0) - , log1p = __webpack_require__(101) - , sqrt = Math.sqrt - , $acosh = Math.acosh; - -$export($export.S + $export.F * !($acosh - // V8 bug: https://code.google.com/p/v8/issues/detail?id=3509 - && Math.floor($acosh(Number.MAX_VALUE)) == 710 - // Tor Browser bug: Math.acosh(Infinity) -> NaN - && $acosh(Infinity) == Infinity -), 'Math', { - acosh: function acosh(x){ - return (x = +x) < 1 ? NaN : x > 94906265.62425156 - ? Math.log(x) + Math.LN2 - : log1p(x - 1 + sqrt(x - 1) * sqrt(x + 1)); - } -}); - -/***/ }), -/* 166 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.2.2.5 Math.asinh(x) -var $export = __webpack_require__(0) - , $asinh = Math.asinh; - -function asinh(x){ - return !isFinite(x = +x) || x == 0 ? x : x < 0 ? -asinh(-x) : Math.log(x + Math.sqrt(x * x + 1)); -} - -// Tor Browser bug: Math.asinh(0) -> -0 -$export($export.S + $export.F * !($asinh && 1 / $asinh(0) > 0), 'Math', {asinh: asinh}); - -/***/ }), -/* 167 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.2.2.7 Math.atanh(x) -var $export = __webpack_require__(0) - , $atanh = Math.atanh; - -// Tor Browser bug: Math.atanh(-0) -> 0 -$export($export.S + $export.F * !($atanh && 1 / $atanh(-0) < 0), 'Math', { - atanh: function atanh(x){ - return (x = +x) == 0 ? x : Math.log((1 + x) / (1 - x)) / 2; - } -}); - -/***/ }), -/* 168 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.2.2.9 Math.cbrt(x) -var $export = __webpack_require__(0) - , sign = __webpack_require__(74); - -$export($export.S, 'Math', { - cbrt: function cbrt(x){ - return sign(x = +x) * Math.pow(Math.abs(x), 1 / 3); - } -}); - -/***/ }), -/* 169 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.2.2.11 Math.clz32(x) -var $export = __webpack_require__(0); - -$export($export.S, 'Math', { - clz32: function clz32(x){ - return (x >>>= 0) ? 31 - Math.floor(Math.log(x + 0.5) * Math.LOG2E) : 32; - } -}); - -/***/ }), -/* 170 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.2.2.12 Math.cosh(x) -var $export = __webpack_require__(0) - , exp = Math.exp; - -$export($export.S, 'Math', { - cosh: function cosh(x){ - return (exp(x = +x) + exp(-x)) / 2; - } -}); - -/***/ }), -/* 171 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.2.2.14 Math.expm1(x) -var $export = __webpack_require__(0) - , $expm1 = __webpack_require__(73); - -$export($export.S + $export.F * ($expm1 != Math.expm1), 'Math', {expm1: $expm1}); - -/***/ }), -/* 172 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.2.2.16 Math.fround(x) -var $export = __webpack_require__(0) - , sign = __webpack_require__(74) - , pow = Math.pow - , EPSILON = pow(2, -52) - , EPSILON32 = pow(2, -23) - , MAX32 = pow(2, 127) * (2 - EPSILON32) - , MIN32 = pow(2, -126); - -var roundTiesToEven = function(n){ - return n + 1 / EPSILON - 1 / EPSILON; -}; - - -$export($export.S, 'Math', { - fround: function fround(x){ - var $abs = Math.abs(x) - , $sign = sign(x) - , a, result; - if($abs < MIN32)return $sign * roundTiesToEven($abs / MIN32 / EPSILON32) * MIN32 * EPSILON32; - a = (1 + EPSILON32 / EPSILON) * $abs; - result = a - (a - $abs); - if(result > MAX32 || result != result)return $sign * Infinity; - return $sign * result; - } -}); - -/***/ }), -/* 173 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.2.2.17 Math.hypot([value1[, value2[, … ]]]) -var $export = __webpack_require__(0) - , abs = Math.abs; - -$export($export.S, 'Math', { - hypot: function hypot(value1, value2){ // eslint-disable-line no-unused-vars - var sum = 0 - , i = 0 - , aLen = arguments.length - , larg = 0 - , arg, div; - while(i < aLen){ - arg = abs(arguments[i++]); - if(larg < arg){ - div = larg / arg; - sum = sum * div * div + 1; - larg = arg; - } else if(arg > 0){ - div = arg / larg; - sum += div * div; - } else sum += arg; - } - return larg === Infinity ? Infinity : larg * Math.sqrt(sum); - } -}); - -/***/ }), -/* 174 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.2.2.18 Math.imul(x, y) -var $export = __webpack_require__(0) - , $imul = Math.imul; - -// some WebKit versions fails with big numbers, some has wrong arity -$export($export.S + $export.F * __webpack_require__(3)(function(){ - return $imul(0xffffffff, 5) != -5 || $imul.length != 2; -}), 'Math', { - imul: function imul(x, y){ - var UINT16 = 0xffff - , xn = +x - , yn = +y - , xl = UINT16 & xn - , yl = UINT16 & yn; - return 0 | xl * yl + ((UINT16 & xn >>> 16) * yl + xl * (UINT16 & yn >>> 16) << 16 >>> 0); - } -}); - -/***/ }), -/* 175 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.2.2.21 Math.log10(x) -var $export = __webpack_require__(0); - -$export($export.S, 'Math', { - log10: function log10(x){ - return Math.log(x) / Math.LN10; - } -}); - -/***/ }), -/* 176 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.2.2.20 Math.log1p(x) -var $export = __webpack_require__(0); - -$export($export.S, 'Math', {log1p: __webpack_require__(101)}); - -/***/ }), -/* 177 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.2.2.22 Math.log2(x) -var $export = __webpack_require__(0); - -$export($export.S, 'Math', { - log2: function log2(x){ - return Math.log(x) / Math.LN2; - } -}); - -/***/ }), -/* 178 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.2.2.28 Math.sign(x) -var $export = __webpack_require__(0); - -$export($export.S, 'Math', {sign: __webpack_require__(74)}); - -/***/ }), -/* 179 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.2.2.30 Math.sinh(x) -var $export = __webpack_require__(0) - , expm1 = __webpack_require__(73) - , exp = Math.exp; - -// V8 near Chromium 38 has a problem with very small numbers -$export($export.S + $export.F * __webpack_require__(3)(function(){ - return !Math.sinh(-2e-17) != -2e-17; -}), 'Math', { - sinh: function sinh(x){ - return Math.abs(x = +x) < 1 - ? (expm1(x) - expm1(-x)) / 2 - : (exp(x - 1) - exp(-x - 1)) * (Math.E / 2); - } -}); - -/***/ }), -/* 180 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.2.2.33 Math.tanh(x) -var $export = __webpack_require__(0) - , expm1 = __webpack_require__(73) - , exp = Math.exp; - -$export($export.S, 'Math', { - tanh: function tanh(x){ - var a = expm1(x = +x) - , b = expm1(-x); - return a == Infinity ? 1 : b == Infinity ? -1 : (a - b) / (exp(x) + exp(-x)); - } -}); - -/***/ }), -/* 181 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.2.2.34 Math.trunc(x) -var $export = __webpack_require__(0); - -$export($export.S, 'Math', { - trunc: function trunc(it){ - return (it > 0 ? Math.floor : Math.ceil)(it); - } -}); - -/***/ }), -/* 182 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var global = __webpack_require__(2) - , has = __webpack_require__(10) - , cof = __webpack_require__(18) - , inheritIfRequired = __webpack_require__(68) - , toPrimitive = __webpack_require__(23) - , fails = __webpack_require__(3) - , gOPN = __webpack_require__(35).f - , gOPD = __webpack_require__(16).f - , dP = __webpack_require__(7).f - , $trim = __webpack_require__(46).trim - , NUMBER = 'Number' - , $Number = global[NUMBER] - , Base = $Number - , proto = $Number.prototype - // Opera ~12 has broken Object#toString - , BROKEN_COF = cof(__webpack_require__(34)(proto)) == NUMBER - , TRIM = 'trim' in String.prototype; - -// 7.1.3 ToNumber(argument) -var toNumber = function(argument){ - var it = toPrimitive(argument, false); - if(typeof it == 'string' && it.length > 2){ - it = TRIM ? it.trim() : $trim(it, 3); - var first = it.charCodeAt(0) - , third, radix, maxCode; - if(first === 43 || first === 45){ - third = it.charCodeAt(2); - if(third === 88 || third === 120)return NaN; // Number('+0x1') should be NaN, old V8 fix - } else if(first === 48){ - switch(it.charCodeAt(1)){ - case 66 : case 98 : radix = 2; maxCode = 49; break; // fast equal /^0b[01]+$/i - case 79 : case 111 : radix = 8; maxCode = 55; break; // fast equal /^0o[0-7]+$/i - default : return +it; - } - for(var digits = it.slice(2), i = 0, l = digits.length, code; i < l; i++){ - code = digits.charCodeAt(i); - // parseInt parses a string to a first unavailable symbol - // but ToNumber should return NaN if a string contains unavailable symbols - if(code < 48 || code > maxCode)return NaN; - } return parseInt(digits, radix); - } - } return +it; -}; - -if(!$Number(' 0o1') || !$Number('0b1') || $Number('+0x1')){ - $Number = function Number(value){ - var it = arguments.length < 1 ? 0 : value - , that = this; - return that instanceof $Number - // check on 1..constructor(foo) case - && (BROKEN_COF ? fails(function(){ proto.valueOf.call(that); }) : cof(that) != NUMBER) - ? inheritIfRequired(new Base(toNumber(it)), that, $Number) : toNumber(it); - }; - for(var keys = __webpack_require__(6) ? gOPN(Base) : ( - // ES3: - 'MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,' + - // ES6 (in case, if modules with ES6 Number statics required before): - 'EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,' + - 'MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger' - ).split(','), j = 0, key; keys.length > j; j++){ - if(has(Base, key = keys[j]) && !has($Number, key)){ - dP($Number, key, gOPD(Base, key)); - } - } - $Number.prototype = proto; - proto.constructor = $Number; - __webpack_require__(13)(global, NUMBER, $Number); -} - -/***/ }), -/* 183 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.1.2.1 Number.EPSILON -var $export = __webpack_require__(0); - -$export($export.S, 'Number', {EPSILON: Math.pow(2, -52)}); - -/***/ }), -/* 184 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.1.2.2 Number.isFinite(number) -var $export = __webpack_require__(0) - , _isFinite = __webpack_require__(2).isFinite; - -$export($export.S, 'Number', { - isFinite: function isFinite(it){ - return typeof it == 'number' && _isFinite(it); - } -}); - -/***/ }), -/* 185 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.1.2.3 Number.isInteger(number) -var $export = __webpack_require__(0); - -$export($export.S, 'Number', {isInteger: __webpack_require__(98)}); - -/***/ }), -/* 186 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.1.2.4 Number.isNaN(number) -var $export = __webpack_require__(0); - -$export($export.S, 'Number', { - isNaN: function isNaN(number){ - return number != number; - } -}); - -/***/ }), -/* 187 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.1.2.5 Number.isSafeInteger(number) -var $export = __webpack_require__(0) - , isInteger = __webpack_require__(98) - , abs = Math.abs; - -$export($export.S, 'Number', { - isSafeInteger: function isSafeInteger(number){ - return isInteger(number) && abs(number) <= 0x1fffffffffffff; - } -}); - -/***/ }), -/* 188 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.1.2.6 Number.MAX_SAFE_INTEGER -var $export = __webpack_require__(0); - -$export($export.S, 'Number', {MAX_SAFE_INTEGER: 0x1fffffffffffff}); - -/***/ }), -/* 189 */ -/***/ (function(module, exports, __webpack_require__) { - -// 20.1.2.10 Number.MIN_SAFE_INTEGER -var $export = __webpack_require__(0); - -$export($export.S, 'Number', {MIN_SAFE_INTEGER: -0x1fffffffffffff}); - -/***/ }), -/* 190 */ -/***/ (function(module, exports, __webpack_require__) { - -var $export = __webpack_require__(0) - , $parseFloat = __webpack_require__(108); -// 20.1.2.12 Number.parseFloat(string) -$export($export.S + $export.F * (Number.parseFloat != $parseFloat), 'Number', {parseFloat: $parseFloat}); - -/***/ }), -/* 191 */ -/***/ (function(module, exports, __webpack_require__) { - -var $export = __webpack_require__(0) - , $parseInt = __webpack_require__(109); -// 20.1.2.13 Number.parseInt(string, radix) -$export($export.S + $export.F * (Number.parseInt != $parseInt), 'Number', {parseInt: $parseInt}); - -/***/ }), -/* 192 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , toInteger = __webpack_require__(31) - , aNumberValue = __webpack_require__(89) - , repeat = __webpack_require__(81) - , $toFixed = 1..toFixed - , floor = Math.floor - , data = [0, 0, 0, 0, 0, 0] - , ERROR = 'Number.toFixed: incorrect invocation!' - , ZERO = '0'; - -var multiply = function(n, c){ - var i = -1 - , c2 = c; - while(++i < 6){ - c2 += n * data[i]; - data[i] = c2 % 1e7; - c2 = floor(c2 / 1e7); - } -}; -var divide = function(n){ - var i = 6 - , c = 0; - while(--i >= 0){ - c += data[i]; - data[i] = floor(c / n); - c = (c % n) * 1e7; - } -}; -var numToString = function(){ - var i = 6 - , s = ''; - while(--i >= 0){ - if(s !== '' || i === 0 || data[i] !== 0){ - var t = String(data[i]); - s = s === '' ? t : s + repeat.call(ZERO, 7 - t.length) + t; - } - } return s; -}; -var pow = function(x, n, acc){ - return n === 0 ? acc : n % 2 === 1 ? pow(x, n - 1, acc * x) : pow(x * x, n / 2, acc); -}; -var log = function(x){ - var n = 0 - , x2 = x; - while(x2 >= 4096){ - n += 12; - x2 /= 4096; - } - while(x2 >= 2){ - n += 1; - x2 /= 2; - } return n; -}; - -$export($export.P + $export.F * (!!$toFixed && ( - 0.00008.toFixed(3) !== '0.000' || - 0.9.toFixed(0) !== '1' || - 1.255.toFixed(2) !== '1.25' || - 1000000000000000128..toFixed(0) !== '1000000000000000128' -) || !__webpack_require__(3)(function(){ - // V8 ~ Android 4.3- - $toFixed.call({}); -})), 'Number', { - toFixed: function toFixed(fractionDigits){ - var x = aNumberValue(this, ERROR) - , f = toInteger(fractionDigits) - , s = '' - , m = ZERO - , e, z, j, k; - if(f < 0 || f > 20)throw RangeError(ERROR); - if(x != x)return 'NaN'; - if(x <= -1e21 || x >= 1e21)return String(x); - if(x < 0){ - s = '-'; - x = -x; - } - if(x > 1e-21){ - e = log(x * pow(2, 69, 1)) - 69; - z = e < 0 ? x * pow(2, -e, 1) : x / pow(2, e, 1); - z *= 0x10000000000000; - e = 52 - e; - if(e > 0){ - multiply(0, z); - j = f; - while(j >= 7){ - multiply(1e7, 0); - j -= 7; - } - multiply(pow(10, j, 1), 0); - j = e - 1; - while(j >= 23){ - divide(1 << 23); - j -= 23; - } - divide(1 << j); - multiply(1, 1); - divide(2); - m = numToString(); - } else { - multiply(0, z); - multiply(1 << -e, 0); - m = numToString() + repeat.call(ZERO, f); - } - } - if(f > 0){ - k = m.length; - m = s + (k <= f ? '0.' + repeat.call(ZERO, f - k) + m : m.slice(0, k - f) + '.' + m.slice(k - f)); - } else { - m = s + m; - } return m; - } -}); - -/***/ }), -/* 193 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , $fails = __webpack_require__(3) - , aNumberValue = __webpack_require__(89) - , $toPrecision = 1..toPrecision; - -$export($export.P + $export.F * ($fails(function(){ - // IE7- - return $toPrecision.call(1, undefined) !== '1'; -}) || !$fails(function(){ - // V8 ~ Android 4.3- - $toPrecision.call({}); -})), 'Number', { - toPrecision: function toPrecision(precision){ - var that = aNumberValue(this, 'Number#toPrecision: incorrect invocation!'); - return precision === undefined ? $toPrecision.call(that) : $toPrecision.call(that, precision); - } -}); - -/***/ }), -/* 194 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.1.3.1 Object.assign(target, source) -var $export = __webpack_require__(0); - -$export($export.S + $export.F, 'Object', {assign: __webpack_require__(102)}); - -/***/ }), -/* 195 */ -/***/ (function(module, exports, __webpack_require__) { - -var $export = __webpack_require__(0) -// 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties]) -$export($export.S, 'Object', {create: __webpack_require__(34)}); - -/***/ }), -/* 196 */ -/***/ (function(module, exports, __webpack_require__) { - -var $export = __webpack_require__(0); -// 19.1.2.3 / 15.2.3.7 Object.defineProperties(O, Properties) -$export($export.S + $export.F * !__webpack_require__(6), 'Object', {defineProperties: __webpack_require__(103)}); - -/***/ }), -/* 197 */ -/***/ (function(module, exports, __webpack_require__) { - -var $export = __webpack_require__(0); -// 19.1.2.4 / 15.2.3.6 Object.defineProperty(O, P, Attributes) -$export($export.S + $export.F * !__webpack_require__(6), 'Object', {defineProperty: __webpack_require__(7).f}); - -/***/ }), -/* 198 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.1.2.5 Object.freeze(O) -var isObject = __webpack_require__(4) - , meta = __webpack_require__(29).onFreeze; - -__webpack_require__(22)('freeze', function($freeze){ - return function freeze(it){ - return $freeze && isObject(it) ? $freeze(meta(it)) : it; - }; -}); - -/***/ }), -/* 199 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.1.2.6 Object.getOwnPropertyDescriptor(O, P) -var toIObject = __webpack_require__(15) - , $getOwnPropertyDescriptor = __webpack_require__(16).f; - -__webpack_require__(22)('getOwnPropertyDescriptor', function(){ - return function getOwnPropertyDescriptor(it, key){ - return $getOwnPropertyDescriptor(toIObject(it), key); - }; -}); - -/***/ }), -/* 200 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.1.2.7 Object.getOwnPropertyNames(O) -__webpack_require__(22)('getOwnPropertyNames', function(){ - return __webpack_require__(104).f; -}); - -/***/ }), -/* 201 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.1.2.9 Object.getPrototypeOf(O) -var toObject = __webpack_require__(9) - , $getPrototypeOf = __webpack_require__(17); - -__webpack_require__(22)('getPrototypeOf', function(){ - return function getPrototypeOf(it){ - return $getPrototypeOf(toObject(it)); - }; -}); - -/***/ }), -/* 202 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.1.2.11 Object.isExtensible(O) -var isObject = __webpack_require__(4); - -__webpack_require__(22)('isExtensible', function($isExtensible){ - return function isExtensible(it){ - return isObject(it) ? $isExtensible ? $isExtensible(it) : true : false; - }; -}); - -/***/ }), -/* 203 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.1.2.12 Object.isFrozen(O) -var isObject = __webpack_require__(4); - -__webpack_require__(22)('isFrozen', function($isFrozen){ - return function isFrozen(it){ - return isObject(it) ? $isFrozen ? $isFrozen(it) : false : true; - }; -}); - -/***/ }), -/* 204 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.1.2.13 Object.isSealed(O) -var isObject = __webpack_require__(4); - -__webpack_require__(22)('isSealed', function($isSealed){ - return function isSealed(it){ - return isObject(it) ? $isSealed ? $isSealed(it) : false : true; - }; -}); - -/***/ }), -/* 205 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.1.3.10 Object.is(value1, value2) -var $export = __webpack_require__(0); -$export($export.S, 'Object', {is: __webpack_require__(110)}); - -/***/ }), -/* 206 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.1.2.14 Object.keys(O) -var toObject = __webpack_require__(9) - , $keys = __webpack_require__(36); - -__webpack_require__(22)('keys', function(){ - return function keys(it){ - return $keys(toObject(it)); - }; -}); - -/***/ }), -/* 207 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.1.2.15 Object.preventExtensions(O) -var isObject = __webpack_require__(4) - , meta = __webpack_require__(29).onFreeze; - -__webpack_require__(22)('preventExtensions', function($preventExtensions){ - return function preventExtensions(it){ - return $preventExtensions && isObject(it) ? $preventExtensions(meta(it)) : it; - }; -}); - -/***/ }), -/* 208 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.1.2.17 Object.seal(O) -var isObject = __webpack_require__(4) - , meta = __webpack_require__(29).onFreeze; - -__webpack_require__(22)('seal', function($seal){ - return function seal(it){ - return $seal && isObject(it) ? $seal(meta(it)) : it; - }; -}); - -/***/ }), -/* 209 */ -/***/ (function(module, exports, __webpack_require__) { - -// 19.1.3.19 Object.setPrototypeOf(O, proto) -var $export = __webpack_require__(0); -$export($export.S, 'Object', {setPrototypeOf: __webpack_require__(76).set}); - -/***/ }), -/* 210 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// 19.1.3.6 Object.prototype.toString() -var classof = __webpack_require__(48) - , test = {}; -test[__webpack_require__(5)('toStringTag')] = 'z'; -if(test + '' != '[object z]'){ - __webpack_require__(13)(Object.prototype, 'toString', function toString(){ - return '[object ' + classof(this) + ']'; - }, true); -} - -/***/ }), -/* 211 */ -/***/ (function(module, exports, __webpack_require__) { - -var $export = __webpack_require__(0) - , $parseFloat = __webpack_require__(108); -// 18.2.4 parseFloat(string) -$export($export.G + $export.F * (parseFloat != $parseFloat), {parseFloat: $parseFloat}); - -/***/ }), -/* 212 */ -/***/ (function(module, exports, __webpack_require__) { - -var $export = __webpack_require__(0) - , $parseInt = __webpack_require__(109); -// 18.2.5 parseInt(string, radix) -$export($export.G + $export.F * (parseInt != $parseInt), {parseInt: $parseInt}); - -/***/ }), -/* 213 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var LIBRARY = __webpack_require__(33) - , global = __webpack_require__(2) - , ctx = __webpack_require__(25) - , classof = __webpack_require__(48) - , $export = __webpack_require__(0) - , isObject = __webpack_require__(4) - , aFunction = __webpack_require__(11) - , anInstance = __webpack_require__(32) - , forOf = __webpack_require__(43) - , speciesConstructor = __webpack_require__(78) - , task = __webpack_require__(83).set - , microtask = __webpack_require__(75)() - , PROMISE = 'Promise' - , TypeError = global.TypeError - , process = global.process - , $Promise = global[PROMISE] - , process = global.process - , isNode = classof(process) == 'process' - , empty = function(){ /* empty */ } - , Internal, GenericPromiseCapability, Wrapper; - -var USE_NATIVE = !!function(){ - try { - // correct subclassing with @@species support - var promise = $Promise.resolve(1) - , FakePromise = (promise.constructor = {})[__webpack_require__(5)('species')] = function(exec){ exec(empty, empty); }; - // unhandled rejections tracking support, NodeJS Promise without it fails @@species test - return (isNode || typeof PromiseRejectionEvent == 'function') && promise.then(empty) instanceof FakePromise; - } catch(e){ /* empty */ } -}(); - -// helpers -var sameConstructor = function(a, b){ - // with library wrapper special case - return a === b || a === $Promise && b === Wrapper; -}; -var isThenable = function(it){ - var then; - return isObject(it) && typeof (then = it.then) == 'function' ? then : false; -}; -var newPromiseCapability = function(C){ - return sameConstructor($Promise, C) - ? new PromiseCapability(C) - : new GenericPromiseCapability(C); -}; -var PromiseCapability = GenericPromiseCapability = function(C){ - var resolve, reject; - this.promise = new C(function($$resolve, $$reject){ - if(resolve !== undefined || reject !== undefined)throw TypeError('Bad Promise constructor'); - resolve = $$resolve; - reject = $$reject; - }); - this.resolve = aFunction(resolve); - this.reject = aFunction(reject); -}; -var perform = function(exec){ - try { - exec(); - } catch(e){ - return {error: e}; - } -}; -var notify = function(promise, isReject){ - if(promise._n)return; - promise._n = true; - var chain = promise._c; - microtask(function(){ - var value = promise._v - , ok = promise._s == 1 - , i = 0; - var run = function(reaction){ - var handler = ok ? reaction.ok : reaction.fail - , resolve = reaction.resolve - , reject = reaction.reject - , domain = reaction.domain - , result, then; - try { - if(handler){ - if(!ok){ - if(promise._h == 2)onHandleUnhandled(promise); - promise._h = 1; - } - if(handler === true)result = value; - else { - if(domain)domain.enter(); - result = handler(value); - if(domain)domain.exit(); - } - if(result === reaction.promise){ - reject(TypeError('Promise-chain cycle')); - } else if(then = isThenable(result)){ - then.call(result, resolve, reject); - } else resolve(result); - } else reject(value); - } catch(e){ - reject(e); - } - }; - while(chain.length > i)run(chain[i++]); // variable length - can't use forEach - promise._c = []; - promise._n = false; - if(isReject && !promise._h)onUnhandled(promise); - }); -}; -var onUnhandled = function(promise){ - task.call(global, function(){ - var value = promise._v - , abrupt, handler, console; - if(isUnhandled(promise)){ - abrupt = perform(function(){ - if(isNode){ - process.emit('unhandledRejection', value, promise); - } else if(handler = global.onunhandledrejection){ - handler({promise: promise, reason: value}); - } else if((console = global.console) && console.error){ - console.error('Unhandled promise rejection', value); - } - }); - // Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should - promise._h = isNode || isUnhandled(promise) ? 2 : 1; - } promise._a = undefined; - if(abrupt)throw abrupt.error; - }); -}; -var isUnhandled = function(promise){ - if(promise._h == 1)return false; - var chain = promise._a || promise._c - , i = 0 - , reaction; - while(chain.length > i){ - reaction = chain[i++]; - if(reaction.fail || !isUnhandled(reaction.promise))return false; - } return true; -}; -var onHandleUnhandled = function(promise){ - task.call(global, function(){ - var handler; - if(isNode){ - process.emit('rejectionHandled', promise); - } else if(handler = global.onrejectionhandled){ - handler({promise: promise, reason: promise._v}); - } - }); -}; -var $reject = function(value){ - var promise = this; - if(promise._d)return; - promise._d = true; - promise = promise._w || promise; // unwrap - promise._v = value; - promise._s = 2; - if(!promise._a)promise._a = promise._c.slice(); - notify(promise, true); -}; -var $resolve = function(value){ - var promise = this - , then; - if(promise._d)return; - promise._d = true; - promise = promise._w || promise; // unwrap - try { - if(promise === value)throw TypeError("Promise can't be resolved itself"); - if(then = isThenable(value)){ - microtask(function(){ - var wrapper = {_w: promise, _d: false}; // wrap - try { - then.call(value, ctx($resolve, wrapper, 1), ctx($reject, wrapper, 1)); - } catch(e){ - $reject.call(wrapper, e); - } - }); - } else { - promise._v = value; - promise._s = 1; - notify(promise, false); - } - } catch(e){ - $reject.call({_w: promise, _d: false}, e); // wrap - } -}; - -// constructor polyfill -if(!USE_NATIVE){ - // 25.4.3.1 Promise(executor) - $Promise = function Promise(executor){ - anInstance(this, $Promise, PROMISE, '_h'); - aFunction(executor); - Internal.call(this); - try { - executor(ctx($resolve, this, 1), ctx($reject, this, 1)); - } catch(err){ - $reject.call(this, err); - } - }; - Internal = function Promise(executor){ - this._c = []; // <- awaiting reactions - this._a = undefined; // <- checked in isUnhandled reactions - this._s = 0; // <- state - this._d = false; // <- done - this._v = undefined; // <- value - this._h = 0; // <- rejection state, 0 - default, 1 - handled, 2 - unhandled - this._n = false; // <- notify - }; - Internal.prototype = __webpack_require__(37)($Promise.prototype, { - // 25.4.5.3 Promise.prototype.then(onFulfilled, onRejected) - then: function then(onFulfilled, onRejected){ - var reaction = newPromiseCapability(speciesConstructor(this, $Promise)); - reaction.ok = typeof onFulfilled == 'function' ? onFulfilled : true; - reaction.fail = typeof onRejected == 'function' && onRejected; - reaction.domain = isNode ? process.domain : undefined; - this._c.push(reaction); - if(this._a)this._a.push(reaction); - if(this._s)notify(this, false); - return reaction.promise; - }, - // 25.4.5.1 Promise.prototype.catch(onRejected) - 'catch': function(onRejected){ - return this.then(undefined, onRejected); - } - }); - PromiseCapability = function(){ - var promise = new Internal; - this.promise = promise; - this.resolve = ctx($resolve, promise, 1); - this.reject = ctx($reject, promise, 1); - }; -} - -$export($export.G + $export.W + $export.F * !USE_NATIVE, {Promise: $Promise}); -__webpack_require__(45)($Promise, PROMISE); -__webpack_require__(38)(PROMISE); -Wrapper = __webpack_require__(24)[PROMISE]; - -// statics -$export($export.S + $export.F * !USE_NATIVE, PROMISE, { - // 25.4.4.5 Promise.reject(r) - reject: function reject(r){ - var capability = newPromiseCapability(this) - , $$reject = capability.reject; - $$reject(r); - return capability.promise; - } -}); -$export($export.S + $export.F * (LIBRARY || !USE_NATIVE), PROMISE, { - // 25.4.4.6 Promise.resolve(x) - resolve: function resolve(x){ - // instanceof instead of internal slot check because we should fix it without replacement native Promise core - if(x instanceof $Promise && sameConstructor(x.constructor, this))return x; - var capability = newPromiseCapability(this) - , $$resolve = capability.resolve; - $$resolve(x); - return capability.promise; - } -}); -$export($export.S + $export.F * !(USE_NATIVE && __webpack_require__(57)(function(iter){ - $Promise.all(iter)['catch'](empty); -})), PROMISE, { - // 25.4.4.1 Promise.all(iterable) - all: function all(iterable){ - var C = this - , capability = newPromiseCapability(C) - , resolve = capability.resolve - , reject = capability.reject; - var abrupt = perform(function(){ - var values = [] - , index = 0 - , remaining = 1; - forOf(iterable, false, function(promise){ - var $index = index++ - , alreadyCalled = false; - values.push(undefined); - remaining++; - C.resolve(promise).then(function(value){ - if(alreadyCalled)return; - alreadyCalled = true; - values[$index] = value; - --remaining || resolve(values); - }, reject); - }); - --remaining || resolve(values); - }); - if(abrupt)reject(abrupt.error); - return capability.promise; - }, - // 25.4.4.4 Promise.race(iterable) - race: function race(iterable){ - var C = this - , capability = newPromiseCapability(C) - , reject = capability.reject; - var abrupt = perform(function(){ - forOf(iterable, false, function(promise){ - C.resolve(promise).then(capability.resolve, reject); - }); - }); - if(abrupt)reject(abrupt.error); - return capability.promise; - } -}); - -/***/ }), -/* 214 */ -/***/ (function(module, exports, __webpack_require__) { - -// 26.1.1 Reflect.apply(target, thisArgument, argumentsList) -var $export = __webpack_require__(0) - , aFunction = __webpack_require__(11) - , anObject = __webpack_require__(1) - , rApply = (__webpack_require__(2).Reflect || {}).apply - , fApply = Function.apply; -// MS Edge argumentsList argument is optional -$export($export.S + $export.F * !__webpack_require__(3)(function(){ - rApply(function(){}); -}), 'Reflect', { - apply: function apply(target, thisArgument, argumentsList){ - var T = aFunction(target) - , L = anObject(argumentsList); - return rApply ? rApply(T, thisArgument, L) : fApply.call(T, thisArgument, L); - } -}); - -/***/ }), -/* 215 */ -/***/ (function(module, exports, __webpack_require__) { - -// 26.1.2 Reflect.construct(target, argumentsList [, newTarget]) -var $export = __webpack_require__(0) - , create = __webpack_require__(34) - , aFunction = __webpack_require__(11) - , anObject = __webpack_require__(1) - , isObject = __webpack_require__(4) - , fails = __webpack_require__(3) - , bind = __webpack_require__(93) - , rConstruct = (__webpack_require__(2).Reflect || {}).construct; - -// MS Edge supports only 2 arguments and argumentsList argument is optional -// FF Nightly sets third argument as `new.target`, but does not create `this` from it -var NEW_TARGET_BUG = fails(function(){ - function F(){} - return !(rConstruct(function(){}, [], F) instanceof F); -}); -var ARGS_BUG = !fails(function(){ - rConstruct(function(){}); -}); - -$export($export.S + $export.F * (NEW_TARGET_BUG || ARGS_BUG), 'Reflect', { - construct: function construct(Target, args /*, newTarget*/){ - aFunction(Target); - anObject(args); - var newTarget = arguments.length < 3 ? Target : aFunction(arguments[2]); - if(ARGS_BUG && !NEW_TARGET_BUG)return rConstruct(Target, args, newTarget); - if(Target == newTarget){ - // w/o altered newTarget, optimization for 0-4 arguments - switch(args.length){ - case 0: return new Target; - case 1: return new Target(args[0]); - case 2: return new Target(args[0], args[1]); - case 3: return new Target(args[0], args[1], args[2]); - case 4: return new Target(args[0], args[1], args[2], args[3]); - } - // w/o altered newTarget, lot of arguments case - var $args = [null]; - $args.push.apply($args, args); - return new (bind.apply(Target, $args)); - } - // with altered newTarget, not support built-in constructors - var proto = newTarget.prototype - , instance = create(isObject(proto) ? proto : Object.prototype) - , result = Function.apply.call(Target, instance, args); - return isObject(result) ? result : instance; - } -}); - -/***/ }), -/* 216 */ -/***/ (function(module, exports, __webpack_require__) { - -// 26.1.3 Reflect.defineProperty(target, propertyKey, attributes) -var dP = __webpack_require__(7) - , $export = __webpack_require__(0) - , anObject = __webpack_require__(1) - , toPrimitive = __webpack_require__(23); - -// MS Edge has broken Reflect.defineProperty - throwing instead of returning false -$export($export.S + $export.F * __webpack_require__(3)(function(){ - Reflect.defineProperty(dP.f({}, 1, {value: 1}), 1, {value: 2}); -}), 'Reflect', { - defineProperty: function defineProperty(target, propertyKey, attributes){ - anObject(target); - propertyKey = toPrimitive(propertyKey, true); - anObject(attributes); - try { - dP.f(target, propertyKey, attributes); - return true; - } catch(e){ - return false; - } - } -}); - -/***/ }), -/* 217 */ -/***/ (function(module, exports, __webpack_require__) { - -// 26.1.4 Reflect.deleteProperty(target, propertyKey) -var $export = __webpack_require__(0) - , gOPD = __webpack_require__(16).f - , anObject = __webpack_require__(1); - -$export($export.S, 'Reflect', { - deleteProperty: function deleteProperty(target, propertyKey){ - var desc = gOPD(anObject(target), propertyKey); - return desc && !desc.configurable ? false : delete target[propertyKey]; - } -}); - -/***/ }), -/* 218 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// 26.1.5 Reflect.enumerate(target) -var $export = __webpack_require__(0) - , anObject = __webpack_require__(1); -var Enumerate = function(iterated){ - this._t = anObject(iterated); // target - this._i = 0; // next index - var keys = this._k = [] // keys - , key; - for(key in iterated)keys.push(key); -}; -__webpack_require__(71)(Enumerate, 'Object', function(){ - var that = this - , keys = that._k - , key; - do { - if(that._i >= keys.length)return {value: undefined, done: true}; - } while(!((key = keys[that._i++]) in that._t)); - return {value: key, done: false}; -}); - -$export($export.S, 'Reflect', { - enumerate: function enumerate(target){ - return new Enumerate(target); - } -}); - -/***/ }), -/* 219 */ -/***/ (function(module, exports, __webpack_require__) { - -// 26.1.7 Reflect.getOwnPropertyDescriptor(target, propertyKey) -var gOPD = __webpack_require__(16) - , $export = __webpack_require__(0) - , anObject = __webpack_require__(1); - -$export($export.S, 'Reflect', { - getOwnPropertyDescriptor: function getOwnPropertyDescriptor(target, propertyKey){ - return gOPD.f(anObject(target), propertyKey); - } -}); - -/***/ }), -/* 220 */ -/***/ (function(module, exports, __webpack_require__) { - -// 26.1.8 Reflect.getPrototypeOf(target) -var $export = __webpack_require__(0) - , getProto = __webpack_require__(17) - , anObject = __webpack_require__(1); - -$export($export.S, 'Reflect', { - getPrototypeOf: function getPrototypeOf(target){ - return getProto(anObject(target)); - } -}); - -/***/ }), -/* 221 */ -/***/ (function(module, exports, __webpack_require__) { - -// 26.1.6 Reflect.get(target, propertyKey [, receiver]) -var gOPD = __webpack_require__(16) - , getPrototypeOf = __webpack_require__(17) - , has = __webpack_require__(10) - , $export = __webpack_require__(0) - , isObject = __webpack_require__(4) - , anObject = __webpack_require__(1); - -function get(target, propertyKey/*, receiver*/){ - var receiver = arguments.length < 3 ? target : arguments[2] - , desc, proto; - if(anObject(target) === receiver)return target[propertyKey]; - if(desc = gOPD.f(target, propertyKey))return has(desc, 'value') - ? desc.value - : desc.get !== undefined - ? desc.get.call(receiver) - : undefined; - if(isObject(proto = getPrototypeOf(target)))return get(proto, propertyKey, receiver); -} - -$export($export.S, 'Reflect', {get: get}); - -/***/ }), -/* 222 */ -/***/ (function(module, exports, __webpack_require__) { - -// 26.1.9 Reflect.has(target, propertyKey) -var $export = __webpack_require__(0); - -$export($export.S, 'Reflect', { - has: function has(target, propertyKey){ - return propertyKey in target; - } -}); - -/***/ }), -/* 223 */ -/***/ (function(module, exports, __webpack_require__) { - -// 26.1.10 Reflect.isExtensible(target) -var $export = __webpack_require__(0) - , anObject = __webpack_require__(1) - , $isExtensible = Object.isExtensible; - -$export($export.S, 'Reflect', { - isExtensible: function isExtensible(target){ - anObject(target); - return $isExtensible ? $isExtensible(target) : true; - } -}); - -/***/ }), -/* 224 */ -/***/ (function(module, exports, __webpack_require__) { - -// 26.1.11 Reflect.ownKeys(target) -var $export = __webpack_require__(0); - -$export($export.S, 'Reflect', {ownKeys: __webpack_require__(107)}); - -/***/ }), -/* 225 */ -/***/ (function(module, exports, __webpack_require__) { - -// 26.1.12 Reflect.preventExtensions(target) -var $export = __webpack_require__(0) - , anObject = __webpack_require__(1) - , $preventExtensions = Object.preventExtensions; - -$export($export.S, 'Reflect', { - preventExtensions: function preventExtensions(target){ - anObject(target); - try { - if($preventExtensions)$preventExtensions(target); - return true; - } catch(e){ - return false; - } - } -}); - -/***/ }), -/* 226 */ -/***/ (function(module, exports, __webpack_require__) { - -// 26.1.14 Reflect.setPrototypeOf(target, proto) -var $export = __webpack_require__(0) - , setProto = __webpack_require__(76); - -if(setProto)$export($export.S, 'Reflect', { - setPrototypeOf: function setPrototypeOf(target, proto){ - setProto.check(target, proto); - try { - setProto.set(target, proto); - return true; - } catch(e){ - return false; - } - } -}); - -/***/ }), -/* 227 */ -/***/ (function(module, exports, __webpack_require__) { - -// 26.1.13 Reflect.set(target, propertyKey, V [, receiver]) -var dP = __webpack_require__(7) - , gOPD = __webpack_require__(16) - , getPrototypeOf = __webpack_require__(17) - , has = __webpack_require__(10) - , $export = __webpack_require__(0) - , createDesc = __webpack_require__(30) - , anObject = __webpack_require__(1) - , isObject = __webpack_require__(4); - -function set(target, propertyKey, V/*, receiver*/){ - var receiver = arguments.length < 4 ? target : arguments[3] - , ownDesc = gOPD.f(anObject(target), propertyKey) - , existingDescriptor, proto; - if(!ownDesc){ - if(isObject(proto = getPrototypeOf(target))){ - return set(proto, propertyKey, V, receiver); - } - ownDesc = createDesc(0); - } - if(has(ownDesc, 'value')){ - if(ownDesc.writable === false || !isObject(receiver))return false; - existingDescriptor = gOPD.f(receiver, propertyKey) || createDesc(0); - existingDescriptor.value = V; - dP.f(receiver, propertyKey, existingDescriptor); - return true; - } - return ownDesc.set === undefined ? false : (ownDesc.set.call(receiver, V), true); -} - -$export($export.S, 'Reflect', {set: set}); - -/***/ }), -/* 228 */ -/***/ (function(module, exports, __webpack_require__) { - -var global = __webpack_require__(2) - , inheritIfRequired = __webpack_require__(68) - , dP = __webpack_require__(7).f - , gOPN = __webpack_require__(35).f - , isRegExp = __webpack_require__(56) - , $flags = __webpack_require__(54) - , $RegExp = global.RegExp - , Base = $RegExp - , proto = $RegExp.prototype - , re1 = /a/g - , re2 = /a/g - // "new" creates a new object, old webkit buggy here - , CORRECT_NEW = new $RegExp(re1) !== re1; - -if(__webpack_require__(6) && (!CORRECT_NEW || __webpack_require__(3)(function(){ - re2[__webpack_require__(5)('match')] = false; - // RegExp constructor can alter flags and IsRegExp works correct with @@match - return $RegExp(re1) != re1 || $RegExp(re2) == re2 || $RegExp(re1, 'i') != '/a/i'; -}))){ - $RegExp = function RegExp(p, f){ - var tiRE = this instanceof $RegExp - , piRE = isRegExp(p) - , fiU = f === undefined; - return !tiRE && piRE && p.constructor === $RegExp && fiU ? p - : inheritIfRequired(CORRECT_NEW - ? new Base(piRE && !fiU ? p.source : p, f) - : Base((piRE = p instanceof $RegExp) ? p.source : p, piRE && fiU ? $flags.call(p) : f) - , tiRE ? this : proto, $RegExp); - }; - var proxy = function(key){ - key in $RegExp || dP($RegExp, key, { - configurable: true, - get: function(){ return Base[key]; }, - set: function(it){ Base[key] = it; } - }); - }; - for(var keys = gOPN(Base), i = 0; keys.length > i; )proxy(keys[i++]); - proto.constructor = $RegExp; - $RegExp.prototype = proto; - __webpack_require__(13)(global, 'RegExp', $RegExp); -} - -__webpack_require__(38)('RegExp'); - -/***/ }), -/* 229 */ -/***/ (function(module, exports, __webpack_require__) { - -// @@match logic -__webpack_require__(53)('match', 1, function(defined, MATCH, $match){ - // 21.1.3.11 String.prototype.match(regexp) - return [function match(regexp){ - 'use strict'; - var O = defined(this) - , fn = regexp == undefined ? undefined : regexp[MATCH]; - return fn !== undefined ? fn.call(regexp, O) : new RegExp(regexp)[MATCH](String(O)); - }, $match]; -}); - -/***/ }), -/* 230 */ -/***/ (function(module, exports, __webpack_require__) { - -// @@replace logic -__webpack_require__(53)('replace', 2, function(defined, REPLACE, $replace){ - // 21.1.3.14 String.prototype.replace(searchValue, replaceValue) - return [function replace(searchValue, replaceValue){ - 'use strict'; - var O = defined(this) - , fn = searchValue == undefined ? undefined : searchValue[REPLACE]; - return fn !== undefined - ? fn.call(searchValue, O, replaceValue) - : $replace.call(String(O), searchValue, replaceValue); - }, $replace]; -}); - -/***/ }), -/* 231 */ -/***/ (function(module, exports, __webpack_require__) { - -// @@search logic -__webpack_require__(53)('search', 1, function(defined, SEARCH, $search){ - // 21.1.3.15 String.prototype.search(regexp) - return [function search(regexp){ - 'use strict'; - var O = defined(this) - , fn = regexp == undefined ? undefined : regexp[SEARCH]; - return fn !== undefined ? fn.call(regexp, O) : new RegExp(regexp)[SEARCH](String(O)); - }, $search]; -}); - -/***/ }), -/* 232 */ -/***/ (function(module, exports, __webpack_require__) { - -// @@split logic -__webpack_require__(53)('split', 2, function(defined, SPLIT, $split){ - 'use strict'; - var isRegExp = __webpack_require__(56) - , _split = $split - , $push = [].push - , $SPLIT = 'split' - , LENGTH = 'length' - , LAST_INDEX = 'lastIndex'; - if( - 'abbc'[$SPLIT](/(b)*/)[1] == 'c' || - 'test'[$SPLIT](/(?:)/, -1)[LENGTH] != 4 || - 'ab'[$SPLIT](/(?:ab)*/)[LENGTH] != 2 || - '.'[$SPLIT](/(.?)(.?)/)[LENGTH] != 4 || - '.'[$SPLIT](/()()/)[LENGTH] > 1 || - ''[$SPLIT](/.?/)[LENGTH] - ){ - var NPCG = /()??/.exec('')[1] === undefined; // nonparticipating capturing group - // based on es5-shim implementation, need to rework it - $split = function(separator, limit){ - var string = String(this); - if(separator === undefined && limit === 0)return []; - // If `separator` is not a regex, use native split - if(!isRegExp(separator))return _split.call(string, separator, limit); - var output = []; - var flags = (separator.ignoreCase ? 'i' : '') + - (separator.multiline ? 'm' : '') + - (separator.unicode ? 'u' : '') + - (separator.sticky ? 'y' : ''); - var lastLastIndex = 0; - var splitLimit = limit === undefined ? 4294967295 : limit >>> 0; - // Make `global` and avoid `lastIndex` issues by working with a copy - var separatorCopy = new RegExp(separator.source, flags + 'g'); - var separator2, match, lastIndex, lastLength, i; - // Doesn't need flags gy, but they don't hurt - if(!NPCG)separator2 = new RegExp('^' + separatorCopy.source + '$(?!\\s)', flags); - while(match = separatorCopy.exec(string)){ - // `separatorCopy.lastIndex` is not reliable cross-browser - lastIndex = match.index + match[0][LENGTH]; - if(lastIndex > lastLastIndex){ - output.push(string.slice(lastLastIndex, match.index)); - // Fix browsers whose `exec` methods don't consistently return `undefined` for NPCG - if(!NPCG && match[LENGTH] > 1)match[0].replace(separator2, function(){ - for(i = 1; i < arguments[LENGTH] - 2; i++)if(arguments[i] === undefined)match[i] = undefined; - }); - if(match[LENGTH] > 1 && match.index < string[LENGTH])$push.apply(output, match.slice(1)); - lastLength = match[0][LENGTH]; - lastLastIndex = lastIndex; - if(output[LENGTH] >= splitLimit)break; - } - if(separatorCopy[LAST_INDEX] === match.index)separatorCopy[LAST_INDEX]++; // Avoid an infinite loop - } - if(lastLastIndex === string[LENGTH]){ - if(lastLength || !separatorCopy.test(''))output.push(''); - } else output.push(string.slice(lastLastIndex)); - return output[LENGTH] > splitLimit ? output.slice(0, splitLimit) : output; - }; - // Chakra, V8 - } else if('0'[$SPLIT](undefined, 0)[LENGTH]){ - $split = function(separator, limit){ - return separator === undefined && limit === 0 ? [] : _split.call(this, separator, limit); - }; - } - // 21.1.3.17 String.prototype.split(separator, limit) - return [function split(separator, limit){ - var O = defined(this) - , fn = separator == undefined ? undefined : separator[SPLIT]; - return fn !== undefined ? fn.call(separator, O, limit) : $split.call(String(O), separator, limit); - }, $split]; -}); - -/***/ }), -/* 233 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -__webpack_require__(114); -var anObject = __webpack_require__(1) - , $flags = __webpack_require__(54) - , DESCRIPTORS = __webpack_require__(6) - , TO_STRING = 'toString' - , $toString = /./[TO_STRING]; - -var define = function(fn){ - __webpack_require__(13)(RegExp.prototype, TO_STRING, fn, true); -}; - -// 21.2.5.14 RegExp.prototype.toString() -if(__webpack_require__(3)(function(){ return $toString.call({source: 'a', flags: 'b'}) != '/a/b'; })){ - define(function toString(){ - var R = anObject(this); - return '/'.concat(R.source, '/', - 'flags' in R ? R.flags : !DESCRIPTORS && R instanceof RegExp ? $flags.call(R) : undefined); - }); -// FF44- RegExp#toString has a wrong name -} else if($toString.name != TO_STRING){ - define(function toString(){ - return $toString.call(this); - }); -} - -/***/ }), -/* 234 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// B.2.3.2 String.prototype.anchor(name) -__webpack_require__(14)('anchor', function(createHTML){ - return function anchor(name){ - return createHTML(this, 'a', 'name', name); - } -}); - -/***/ }), -/* 235 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// B.2.3.3 String.prototype.big() -__webpack_require__(14)('big', function(createHTML){ - return function big(){ - return createHTML(this, 'big', '', ''); - } -}); - -/***/ }), -/* 236 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// B.2.3.4 String.prototype.blink() -__webpack_require__(14)('blink', function(createHTML){ - return function blink(){ - return createHTML(this, 'blink', '', ''); - } -}); - -/***/ }), -/* 237 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// B.2.3.5 String.prototype.bold() -__webpack_require__(14)('bold', function(createHTML){ - return function bold(){ - return createHTML(this, 'b', '', ''); - } -}); - -/***/ }), -/* 238 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , $at = __webpack_require__(79)(false); -$export($export.P, 'String', { - // 21.1.3.3 String.prototype.codePointAt(pos) - codePointAt: function codePointAt(pos){ - return $at(this, pos); - } -}); - -/***/ }), -/* 239 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -// 21.1.3.6 String.prototype.endsWith(searchString [, endPosition]) - -var $export = __webpack_require__(0) - , toLength = __webpack_require__(8) - , context = __webpack_require__(80) - , ENDS_WITH = 'endsWith' - , $endsWith = ''[ENDS_WITH]; - -$export($export.P + $export.F * __webpack_require__(66)(ENDS_WITH), 'String', { - endsWith: function endsWith(searchString /*, endPosition = @length */){ - var that = context(this, searchString, ENDS_WITH) - , endPosition = arguments.length > 1 ? arguments[1] : undefined - , len = toLength(that.length) - , end = endPosition === undefined ? len : Math.min(toLength(endPosition), len) - , search = String(searchString); - return $endsWith - ? $endsWith.call(that, search, end) - : that.slice(end - search.length, end) === search; - } -}); - -/***/ }), -/* 240 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// B.2.3.6 String.prototype.fixed() -__webpack_require__(14)('fixed', function(createHTML){ - return function fixed(){ - return createHTML(this, 'tt', '', ''); - } -}); - -/***/ }), -/* 241 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// B.2.3.7 String.prototype.fontcolor(color) -__webpack_require__(14)('fontcolor', function(createHTML){ - return function fontcolor(color){ - return createHTML(this, 'font', 'color', color); - } -}); - -/***/ }), -/* 242 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// B.2.3.8 String.prototype.fontsize(size) -__webpack_require__(14)('fontsize', function(createHTML){ - return function fontsize(size){ - return createHTML(this, 'font', 'size', size); - } -}); - -/***/ }), -/* 243 */ -/***/ (function(module, exports, __webpack_require__) { - -var $export = __webpack_require__(0) - , toIndex = __webpack_require__(39) - , fromCharCode = String.fromCharCode - , $fromCodePoint = String.fromCodePoint; - -// length should be 1, old FF problem -$export($export.S + $export.F * (!!$fromCodePoint && $fromCodePoint.length != 1), 'String', { - // 21.1.2.2 String.fromCodePoint(...codePoints) - fromCodePoint: function fromCodePoint(x){ // eslint-disable-line no-unused-vars - var res = [] - , aLen = arguments.length - , i = 0 - , code; - while(aLen > i){ - code = +arguments[i++]; - if(toIndex(code, 0x10ffff) !== code)throw RangeError(code + ' is not a valid code point'); - res.push(code < 0x10000 - ? fromCharCode(code) - : fromCharCode(((code -= 0x10000) >> 10) + 0xd800, code % 0x400 + 0xdc00) - ); - } return res.join(''); - } -}); - -/***/ }), -/* 244 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -// 21.1.3.7 String.prototype.includes(searchString, position = 0) - -var $export = __webpack_require__(0) - , context = __webpack_require__(80) - , INCLUDES = 'includes'; - -$export($export.P + $export.F * __webpack_require__(66)(INCLUDES), 'String', { - includes: function includes(searchString /*, position = 0 */){ - return !!~context(this, searchString, INCLUDES) - .indexOf(searchString, arguments.length > 1 ? arguments[1] : undefined); - } -}); - -/***/ }), -/* 245 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// B.2.3.9 String.prototype.italics() -__webpack_require__(14)('italics', function(createHTML){ - return function italics(){ - return createHTML(this, 'i', '', ''); - } -}); - -/***/ }), -/* 246 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $at = __webpack_require__(79)(true); - -// 21.1.3.27 String.prototype[@@iterator]() -__webpack_require__(72)(String, 'String', function(iterated){ - this._t = String(iterated); // target - this._i = 0; // next index -// 21.1.5.2.1 %StringIteratorPrototype%.next() -}, function(){ - var O = this._t - , index = this._i - , point; - if(index >= O.length)return {value: undefined, done: true}; - point = $at(O, index); - this._i += point.length; - return {value: point, done: false}; -}); - -/***/ }), -/* 247 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// B.2.3.10 String.prototype.link(url) -__webpack_require__(14)('link', function(createHTML){ - return function link(url){ - return createHTML(this, 'a', 'href', url); - } -}); - -/***/ }), -/* 248 */ -/***/ (function(module, exports, __webpack_require__) { - -var $export = __webpack_require__(0) - , toIObject = __webpack_require__(15) - , toLength = __webpack_require__(8); - -$export($export.S, 'String', { - // 21.1.2.4 String.raw(callSite, ...substitutions) - raw: function raw(callSite){ - var tpl = toIObject(callSite.raw) - , len = toLength(tpl.length) - , aLen = arguments.length - , res = [] - , i = 0; - while(len > i){ - res.push(String(tpl[i++])); - if(i < aLen)res.push(String(arguments[i])); - } return res.join(''); - } -}); - -/***/ }), -/* 249 */ -/***/ (function(module, exports, __webpack_require__) { - -var $export = __webpack_require__(0); - -$export($export.P, 'String', { - // 21.1.3.13 String.prototype.repeat(count) - repeat: __webpack_require__(81) -}); - -/***/ }), -/* 250 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// B.2.3.11 String.prototype.small() -__webpack_require__(14)('small', function(createHTML){ - return function small(){ - return createHTML(this, 'small', '', ''); - } -}); - -/***/ }), -/* 251 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -// 21.1.3.18 String.prototype.startsWith(searchString [, position ]) - -var $export = __webpack_require__(0) - , toLength = __webpack_require__(8) - , context = __webpack_require__(80) - , STARTS_WITH = 'startsWith' - , $startsWith = ''[STARTS_WITH]; - -$export($export.P + $export.F * __webpack_require__(66)(STARTS_WITH), 'String', { - startsWith: function startsWith(searchString /*, position = 0 */){ - var that = context(this, searchString, STARTS_WITH) - , index = toLength(Math.min(arguments.length > 1 ? arguments[1] : undefined, that.length)) - , search = String(searchString); - return $startsWith - ? $startsWith.call(that, search, index) - : that.slice(index, index + search.length) === search; - } -}); - -/***/ }), -/* 252 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// B.2.3.12 String.prototype.strike() -__webpack_require__(14)('strike', function(createHTML){ - return function strike(){ - return createHTML(this, 'strike', '', ''); - } -}); - -/***/ }), -/* 253 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// B.2.3.13 String.prototype.sub() -__webpack_require__(14)('sub', function(createHTML){ - return function sub(){ - return createHTML(this, 'sub', '', ''); - } -}); - -/***/ }), -/* 254 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// B.2.3.14 String.prototype.sup() -__webpack_require__(14)('sup', function(createHTML){ - return function sup(){ - return createHTML(this, 'sup', '', ''); - } -}); - -/***/ }), -/* 255 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// 21.1.3.25 String.prototype.trim() -__webpack_require__(46)('trim', function($trim){ - return function trim(){ - return $trim(this, 3); - }; -}); - -/***/ }), -/* 256 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// ECMAScript 6 symbols shim -var global = __webpack_require__(2) - , has = __webpack_require__(10) - , DESCRIPTORS = __webpack_require__(6) - , $export = __webpack_require__(0) - , redefine = __webpack_require__(13) - , META = __webpack_require__(29).KEY - , $fails = __webpack_require__(3) - , shared = __webpack_require__(60) - , setToStringTag = __webpack_require__(45) - , uid = __webpack_require__(40) - , wks = __webpack_require__(5) - , wksExt = __webpack_require__(112) - , wksDefine = __webpack_require__(85) - , keyOf = __webpack_require__(132) - , enumKeys = __webpack_require__(131) - , isArray = __webpack_require__(70) - , anObject = __webpack_require__(1) - , toIObject = __webpack_require__(15) - , toPrimitive = __webpack_require__(23) - , createDesc = __webpack_require__(30) - , _create = __webpack_require__(34) - , gOPNExt = __webpack_require__(104) - , $GOPD = __webpack_require__(16) - , $DP = __webpack_require__(7) - , $keys = __webpack_require__(36) - , gOPD = $GOPD.f - , dP = $DP.f - , gOPN = gOPNExt.f - , $Symbol = global.Symbol - , $JSON = global.JSON - , _stringify = $JSON && $JSON.stringify - , PROTOTYPE = 'prototype' - , HIDDEN = wks('_hidden') - , TO_PRIMITIVE = wks('toPrimitive') - , isEnum = {}.propertyIsEnumerable - , SymbolRegistry = shared('symbol-registry') - , AllSymbols = shared('symbols') - , OPSymbols = shared('op-symbols') - , ObjectProto = Object[PROTOTYPE] - , USE_NATIVE = typeof $Symbol == 'function' - , QObject = global.QObject; -// Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173 -var setter = !QObject || !QObject[PROTOTYPE] || !QObject[PROTOTYPE].findChild; - -// fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687 -var setSymbolDesc = DESCRIPTORS && $fails(function(){ - return _create(dP({}, 'a', { - get: function(){ return dP(this, 'a', {value: 7}).a; } - })).a != 7; -}) ? function(it, key, D){ - var protoDesc = gOPD(ObjectProto, key); - if(protoDesc)delete ObjectProto[key]; - dP(it, key, D); - if(protoDesc && it !== ObjectProto)dP(ObjectProto, key, protoDesc); -} : dP; - -var wrap = function(tag){ - var sym = AllSymbols[tag] = _create($Symbol[PROTOTYPE]); - sym._k = tag; - return sym; -}; - -var isSymbol = USE_NATIVE && typeof $Symbol.iterator == 'symbol' ? function(it){ - return typeof it == 'symbol'; -} : function(it){ - return it instanceof $Symbol; -}; - -var $defineProperty = function defineProperty(it, key, D){ - if(it === ObjectProto)$defineProperty(OPSymbols, key, D); - anObject(it); - key = toPrimitive(key, true); - anObject(D); - if(has(AllSymbols, key)){ - if(!D.enumerable){ - if(!has(it, HIDDEN))dP(it, HIDDEN, createDesc(1, {})); - it[HIDDEN][key] = true; - } else { - if(has(it, HIDDEN) && it[HIDDEN][key])it[HIDDEN][key] = false; - D = _create(D, {enumerable: createDesc(0, false)}); - } return setSymbolDesc(it, key, D); - } return dP(it, key, D); -}; -var $defineProperties = function defineProperties(it, P){ - anObject(it); - var keys = enumKeys(P = toIObject(P)) - , i = 0 - , l = keys.length - , key; - while(l > i)$defineProperty(it, key = keys[i++], P[key]); - return it; -}; -var $create = function create(it, P){ - return P === undefined ? _create(it) : $defineProperties(_create(it), P); -}; -var $propertyIsEnumerable = function propertyIsEnumerable(key){ - var E = isEnum.call(this, key = toPrimitive(key, true)); - if(this === ObjectProto && has(AllSymbols, key) && !has(OPSymbols, key))return false; - return E || !has(this, key) || !has(AllSymbols, key) || has(this, HIDDEN) && this[HIDDEN][key] ? E : true; -}; -var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(it, key){ - it = toIObject(it); - key = toPrimitive(key, true); - if(it === ObjectProto && has(AllSymbols, key) && !has(OPSymbols, key))return; - var D = gOPD(it, key); - if(D && has(AllSymbols, key) && !(has(it, HIDDEN) && it[HIDDEN][key]))D.enumerable = true; - return D; -}; -var $getOwnPropertyNames = function getOwnPropertyNames(it){ - var names = gOPN(toIObject(it)) - , result = [] - , i = 0 - , key; - while(names.length > i){ - if(!has(AllSymbols, key = names[i++]) && key != HIDDEN && key != META)result.push(key); - } return result; -}; -var $getOwnPropertySymbols = function getOwnPropertySymbols(it){ - var IS_OP = it === ObjectProto - , names = gOPN(IS_OP ? OPSymbols : toIObject(it)) - , result = [] - , i = 0 - , key; - while(names.length > i){ - if(has(AllSymbols, key = names[i++]) && (IS_OP ? has(ObjectProto, key) : true))result.push(AllSymbols[key]); - } return result; -}; - -// 19.4.1.1 Symbol([description]) -if(!USE_NATIVE){ - $Symbol = function Symbol(){ - if(this instanceof $Symbol)throw TypeError('Symbol is not a constructor!'); - var tag = uid(arguments.length > 0 ? arguments[0] : undefined); - var $set = function(value){ - if(this === ObjectProto)$set.call(OPSymbols, value); - if(has(this, HIDDEN) && has(this[HIDDEN], tag))this[HIDDEN][tag] = false; - setSymbolDesc(this, tag, createDesc(1, value)); - }; - if(DESCRIPTORS && setter)setSymbolDesc(ObjectProto, tag, {configurable: true, set: $set}); - return wrap(tag); - }; - redefine($Symbol[PROTOTYPE], 'toString', function toString(){ - return this._k; - }); - - $GOPD.f = $getOwnPropertyDescriptor; - $DP.f = $defineProperty; - __webpack_require__(35).f = gOPNExt.f = $getOwnPropertyNames; - __webpack_require__(50).f = $propertyIsEnumerable; - __webpack_require__(59).f = $getOwnPropertySymbols; - - if(DESCRIPTORS && !__webpack_require__(33)){ - redefine(ObjectProto, 'propertyIsEnumerable', $propertyIsEnumerable, true); - } - - wksExt.f = function(name){ - return wrap(wks(name)); - } -} - -$export($export.G + $export.W + $export.F * !USE_NATIVE, {Symbol: $Symbol}); - -for(var symbols = ( - // 19.4.2.2, 19.4.2.3, 19.4.2.4, 19.4.2.6, 19.4.2.8, 19.4.2.9, 19.4.2.10, 19.4.2.11, 19.4.2.12, 19.4.2.13, 19.4.2.14 - 'hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables' -).split(','), i = 0; symbols.length > i; )wks(symbols[i++]); - -for(var symbols = $keys(wks.store), i = 0; symbols.length > i; )wksDefine(symbols[i++]); - -$export($export.S + $export.F * !USE_NATIVE, 'Symbol', { - // 19.4.2.1 Symbol.for(key) - 'for': function(key){ - return has(SymbolRegistry, key += '') - ? SymbolRegistry[key] - : SymbolRegistry[key] = $Symbol(key); - }, - // 19.4.2.5 Symbol.keyFor(sym) - keyFor: function keyFor(key){ - if(isSymbol(key))return keyOf(SymbolRegistry, key); - throw TypeError(key + ' is not a symbol!'); - }, - useSetter: function(){ setter = true; }, - useSimple: function(){ setter = false; } -}); - -$export($export.S + $export.F * !USE_NATIVE, 'Object', { - // 19.1.2.2 Object.create(O [, Properties]) - create: $create, - // 19.1.2.4 Object.defineProperty(O, P, Attributes) - defineProperty: $defineProperty, - // 19.1.2.3 Object.defineProperties(O, Properties) - defineProperties: $defineProperties, - // 19.1.2.6 Object.getOwnPropertyDescriptor(O, P) - getOwnPropertyDescriptor: $getOwnPropertyDescriptor, - // 19.1.2.7 Object.getOwnPropertyNames(O) - getOwnPropertyNames: $getOwnPropertyNames, - // 19.1.2.8 Object.getOwnPropertySymbols(O) - getOwnPropertySymbols: $getOwnPropertySymbols -}); - -// 24.3.2 JSON.stringify(value [, replacer [, space]]) -$JSON && $export($export.S + $export.F * (!USE_NATIVE || $fails(function(){ - var S = $Symbol(); - // MS Edge converts symbol values to JSON as {} - // WebKit converts symbol values to JSON as null - // V8 throws on boxed symbols - return _stringify([S]) != '[null]' || _stringify({a: S}) != '{}' || _stringify(Object(S)) != '{}'; -})), 'JSON', { - stringify: function stringify(it){ - if(it === undefined || isSymbol(it))return; // IE8 returns string on undefined - var args = [it] - , i = 1 - , replacer, $replacer; - while(arguments.length > i)args.push(arguments[i++]); - replacer = args[1]; - if(typeof replacer == 'function')$replacer = replacer; - if($replacer || !isArray(replacer))replacer = function(key, value){ - if($replacer)value = $replacer.call(this, key, value); - if(!isSymbol(value))return value; - }; - args[1] = replacer; - return _stringify.apply($JSON, args); - } -}); - -// 19.4.3.4 Symbol.prototype[@@toPrimitive](hint) -$Symbol[PROTOTYPE][TO_PRIMITIVE] || __webpack_require__(12)($Symbol[PROTOTYPE], TO_PRIMITIVE, $Symbol[PROTOTYPE].valueOf); -// 19.4.3.5 Symbol.prototype[@@toStringTag] -setToStringTag($Symbol, 'Symbol'); -// 20.2.1.9 Math[@@toStringTag] -setToStringTag(Math, 'Math', true); -// 24.3.3 JSON[@@toStringTag] -setToStringTag(global.JSON, 'JSON', true); - -/***/ }), -/* 257 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , $typed = __webpack_require__(61) - , buffer = __webpack_require__(84) - , anObject = __webpack_require__(1) - , toIndex = __webpack_require__(39) - , toLength = __webpack_require__(8) - , isObject = __webpack_require__(4) - , ArrayBuffer = __webpack_require__(2).ArrayBuffer - , speciesConstructor = __webpack_require__(78) - , $ArrayBuffer = buffer.ArrayBuffer - , $DataView = buffer.DataView - , $isView = $typed.ABV && ArrayBuffer.isView - , $slice = $ArrayBuffer.prototype.slice - , VIEW = $typed.VIEW - , ARRAY_BUFFER = 'ArrayBuffer'; - -$export($export.G + $export.W + $export.F * (ArrayBuffer !== $ArrayBuffer), {ArrayBuffer: $ArrayBuffer}); - -$export($export.S + $export.F * !$typed.CONSTR, ARRAY_BUFFER, { - // 24.1.3.1 ArrayBuffer.isView(arg) - isView: function isView(it){ - return $isView && $isView(it) || isObject(it) && VIEW in it; - } -}); - -$export($export.P + $export.U + $export.F * __webpack_require__(3)(function(){ - return !new $ArrayBuffer(2).slice(1, undefined).byteLength; -}), ARRAY_BUFFER, { - // 24.1.4.3 ArrayBuffer.prototype.slice(start, end) - slice: function slice(start, end){ - if($slice !== undefined && end === undefined)return $slice.call(anObject(this), start); // FF fix - var len = anObject(this).byteLength - , first = toIndex(start, len) - , final = toIndex(end === undefined ? len : end, len) - , result = new (speciesConstructor(this, $ArrayBuffer))(toLength(final - first)) - , viewS = new $DataView(this) - , viewT = new $DataView(result) - , index = 0; - while(first < final){ - viewT.setUint8(index++, viewS.getUint8(first++)); - } return result; - } -}); - -__webpack_require__(38)(ARRAY_BUFFER); - -/***/ }), -/* 258 */ -/***/ (function(module, exports, __webpack_require__) { - -var $export = __webpack_require__(0); -$export($export.G + $export.W + $export.F * !__webpack_require__(61).ABV, { - DataView: __webpack_require__(84).DataView -}); - -/***/ }), -/* 259 */ -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__(27)('Float32', 4, function(init){ - return function Float32Array(data, byteOffset, length){ - return init(this, data, byteOffset, length); - }; -}); - -/***/ }), -/* 260 */ -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__(27)('Float64', 8, function(init){ - return function Float64Array(data, byteOffset, length){ - return init(this, data, byteOffset, length); - }; -}); - -/***/ }), -/* 261 */ -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__(27)('Int16', 2, function(init){ - return function Int16Array(data, byteOffset, length){ - return init(this, data, byteOffset, length); - }; -}); - -/***/ }), -/* 262 */ -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__(27)('Int32', 4, function(init){ - return function Int32Array(data, byteOffset, length){ - return init(this, data, byteOffset, length); - }; -}); - -/***/ }), -/* 263 */ -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__(27)('Int8', 1, function(init){ - return function Int8Array(data, byteOffset, length){ - return init(this, data, byteOffset, length); - }; -}); - -/***/ }), -/* 264 */ -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__(27)('Uint16', 2, function(init){ - return function Uint16Array(data, byteOffset, length){ - return init(this, data, byteOffset, length); - }; -}); - -/***/ }), -/* 265 */ -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__(27)('Uint32', 4, function(init){ - return function Uint32Array(data, byteOffset, length){ - return init(this, data, byteOffset, length); - }; -}); - -/***/ }), -/* 266 */ -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__(27)('Uint8', 1, function(init){ - return function Uint8Array(data, byteOffset, length){ - return init(this, data, byteOffset, length); - }; -}); - -/***/ }), -/* 267 */ -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__(27)('Uint8', 1, function(init){ - return function Uint8ClampedArray(data, byteOffset, length){ - return init(this, data, byteOffset, length); - }; -}, true); - -/***/ }), -/* 268 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var weak = __webpack_require__(96); - -// 23.4 WeakSet Objects -__webpack_require__(52)('WeakSet', function(get){ - return function WeakSet(){ return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.4.3.1 WeakSet.prototype.add(value) - add: function add(value){ - return weak.def(this, value, true); - } -}, weak, false, true); - -/***/ }), -/* 269 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// https://github.com/tc39/Array.prototype.includes -var $export = __webpack_require__(0) - , $includes = __webpack_require__(51)(true); - -$export($export.P, 'Array', { - includes: function includes(el /*, fromIndex = 0 */){ - return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined); - } -}); - -__webpack_require__(42)('includes'); - -/***/ }), -/* 270 */ -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/rwaldron/tc39-notes/blob/master/es6/2014-09/sept-25.md#510-globalasap-for-enqueuing-a-microtask -var $export = __webpack_require__(0) - , microtask = __webpack_require__(75)() - , process = __webpack_require__(2).process - , isNode = __webpack_require__(18)(process) == 'process'; - -$export($export.G, { - asap: function asap(fn){ - var domain = isNode && process.domain; - microtask(domain ? domain.bind(fn) : fn); - } -}); - -/***/ }), -/* 271 */ -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/ljharb/proposal-is-error -var $export = __webpack_require__(0) - , cof = __webpack_require__(18); - -$export($export.S, 'Error', { - isError: function isError(it){ - return cof(it) === 'Error'; - } -}); - -/***/ }), -/* 272 */ -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__(0); - -$export($export.P + $export.R, 'Map', {toJSON: __webpack_require__(95)('Map')}); - -/***/ }), -/* 273 */ -/***/ (function(module, exports, __webpack_require__) { - -// https://gist.github.com/BrendanEich/4294d5c212a6d2254703 -var $export = __webpack_require__(0); - -$export($export.S, 'Math', { - iaddh: function iaddh(x0, x1, y0, y1){ - var $x0 = x0 >>> 0 - , $x1 = x1 >>> 0 - , $y0 = y0 >>> 0; - return $x1 + (y1 >>> 0) + (($x0 & $y0 | ($x0 | $y0) & ~($x0 + $y0 >>> 0)) >>> 31) | 0; - } -}); - -/***/ }), -/* 274 */ -/***/ (function(module, exports, __webpack_require__) { - -// https://gist.github.com/BrendanEich/4294d5c212a6d2254703 -var $export = __webpack_require__(0); - -$export($export.S, 'Math', { - imulh: function imulh(u, v){ - var UINT16 = 0xffff - , $u = +u - , $v = +v - , u0 = $u & UINT16 - , v0 = $v & UINT16 - , u1 = $u >> 16 - , v1 = $v >> 16 - , t = (u1 * v0 >>> 0) + (u0 * v0 >>> 16); - return u1 * v1 + (t >> 16) + ((u0 * v1 >>> 0) + (t & UINT16) >> 16); - } -}); - -/***/ }), -/* 275 */ -/***/ (function(module, exports, __webpack_require__) { - -// https://gist.github.com/BrendanEich/4294d5c212a6d2254703 -var $export = __webpack_require__(0); - -$export($export.S, 'Math', { - isubh: function isubh(x0, x1, y0, y1){ - var $x0 = x0 >>> 0 - , $x1 = x1 >>> 0 - , $y0 = y0 >>> 0; - return $x1 - (y1 >>> 0) - ((~$x0 & $y0 | ~($x0 ^ $y0) & $x0 - $y0 >>> 0) >>> 31) | 0; - } -}); - -/***/ }), -/* 276 */ -/***/ (function(module, exports, __webpack_require__) { - -// https://gist.github.com/BrendanEich/4294d5c212a6d2254703 -var $export = __webpack_require__(0); - -$export($export.S, 'Math', { - umulh: function umulh(u, v){ - var UINT16 = 0xffff - , $u = +u - , $v = +v - , u0 = $u & UINT16 - , v0 = $v & UINT16 - , u1 = $u >>> 16 - , v1 = $v >>> 16 - , t = (u1 * v0 >>> 0) + (u0 * v0 >>> 16); - return u1 * v1 + (t >>> 16) + ((u0 * v1 >>> 0) + (t & UINT16) >>> 16); - } -}); - -/***/ }), -/* 277 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , toObject = __webpack_require__(9) - , aFunction = __webpack_require__(11) - , $defineProperty = __webpack_require__(7); - -// B.2.2.2 Object.prototype.__defineGetter__(P, getter) -__webpack_require__(6) && $export($export.P + __webpack_require__(58), 'Object', { - __defineGetter__: function __defineGetter__(P, getter){ - $defineProperty.f(toObject(this), P, {get: aFunction(getter), enumerable: true, configurable: true}); - } -}); - -/***/ }), -/* 278 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , toObject = __webpack_require__(9) - , aFunction = __webpack_require__(11) - , $defineProperty = __webpack_require__(7); - -// B.2.2.3 Object.prototype.__defineSetter__(P, setter) -__webpack_require__(6) && $export($export.P + __webpack_require__(58), 'Object', { - __defineSetter__: function __defineSetter__(P, setter){ - $defineProperty.f(toObject(this), P, {set: aFunction(setter), enumerable: true, configurable: true}); - } -}); - -/***/ }), -/* 279 */ -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/tc39/proposal-object-values-entries -var $export = __webpack_require__(0) - , $entries = __webpack_require__(106)(true); - -$export($export.S, 'Object', { - entries: function entries(it){ - return $entries(it); - } -}); - -/***/ }), -/* 280 */ -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/tc39/proposal-object-getownpropertydescriptors -var $export = __webpack_require__(0) - , ownKeys = __webpack_require__(107) - , toIObject = __webpack_require__(15) - , gOPD = __webpack_require__(16) - , createProperty = __webpack_require__(63); - -$export($export.S, 'Object', { - getOwnPropertyDescriptors: function getOwnPropertyDescriptors(object){ - var O = toIObject(object) - , getDesc = gOPD.f - , keys = ownKeys(O) - , result = {} - , i = 0 - , key; - while(keys.length > i)createProperty(result, key = keys[i++], getDesc(O, key)); - return result; - } -}); - -/***/ }), -/* 281 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , toObject = __webpack_require__(9) - , toPrimitive = __webpack_require__(23) - , getPrototypeOf = __webpack_require__(17) - , getOwnPropertyDescriptor = __webpack_require__(16).f; - -// B.2.2.4 Object.prototype.__lookupGetter__(P) -__webpack_require__(6) && $export($export.P + __webpack_require__(58), 'Object', { - __lookupGetter__: function __lookupGetter__(P){ - var O = toObject(this) - , K = toPrimitive(P, true) - , D; - do { - if(D = getOwnPropertyDescriptor(O, K))return D.get; - } while(O = getPrototypeOf(O)); - } -}); - -/***/ }), -/* 282 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var $export = __webpack_require__(0) - , toObject = __webpack_require__(9) - , toPrimitive = __webpack_require__(23) - , getPrototypeOf = __webpack_require__(17) - , getOwnPropertyDescriptor = __webpack_require__(16).f; - -// B.2.2.5 Object.prototype.__lookupSetter__(P) -__webpack_require__(6) && $export($export.P + __webpack_require__(58), 'Object', { - __lookupSetter__: function __lookupSetter__(P){ - var O = toObject(this) - , K = toPrimitive(P, true) - , D; - do { - if(D = getOwnPropertyDescriptor(O, K))return D.set; - } while(O = getPrototypeOf(O)); - } -}); - -/***/ }), -/* 283 */ -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/tc39/proposal-object-values-entries -var $export = __webpack_require__(0) - , $values = __webpack_require__(106)(false); - -$export($export.S, 'Object', { - values: function values(it){ - return $values(it); - } -}); - -/***/ }), -/* 284 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// https://github.com/zenparsing/es-observable -var $export = __webpack_require__(0) - , global = __webpack_require__(2) - , core = __webpack_require__(24) - , microtask = __webpack_require__(75)() - , OBSERVABLE = __webpack_require__(5)('observable') - , aFunction = __webpack_require__(11) - , anObject = __webpack_require__(1) - , anInstance = __webpack_require__(32) - , redefineAll = __webpack_require__(37) - , hide = __webpack_require__(12) - , forOf = __webpack_require__(43) - , RETURN = forOf.RETURN; - -var getMethod = function(fn){ - return fn == null ? undefined : aFunction(fn); -}; - -var cleanupSubscription = function(subscription){ - var cleanup = subscription._c; - if(cleanup){ - subscription._c = undefined; - cleanup(); - } -}; - -var subscriptionClosed = function(subscription){ - return subscription._o === undefined; -}; - -var closeSubscription = function(subscription){ - if(!subscriptionClosed(subscription)){ - subscription._o = undefined; - cleanupSubscription(subscription); - } -}; - -var Subscription = function(observer, subscriber){ - anObject(observer); - this._c = undefined; - this._o = observer; - observer = new SubscriptionObserver(this); - try { - var cleanup = subscriber(observer) - , subscription = cleanup; - if(cleanup != null){ - if(typeof cleanup.unsubscribe === 'function')cleanup = function(){ subscription.unsubscribe(); }; - else aFunction(cleanup); - this._c = cleanup; - } - } catch(e){ - observer.error(e); - return; - } if(subscriptionClosed(this))cleanupSubscription(this); -}; - -Subscription.prototype = redefineAll({}, { - unsubscribe: function unsubscribe(){ closeSubscription(this); } -}); - -var SubscriptionObserver = function(subscription){ - this._s = subscription; -}; - -SubscriptionObserver.prototype = redefineAll({}, { - next: function next(value){ - var subscription = this._s; - if(!subscriptionClosed(subscription)){ - var observer = subscription._o; - try { - var m = getMethod(observer.next); - if(m)return m.call(observer, value); - } catch(e){ - try { - closeSubscription(subscription); - } finally { - throw e; - } - } - } - }, - error: function error(value){ - var subscription = this._s; - if(subscriptionClosed(subscription))throw value; - var observer = subscription._o; - subscription._o = undefined; - try { - var m = getMethod(observer.error); - if(!m)throw value; - value = m.call(observer, value); - } catch(e){ - try { - cleanupSubscription(subscription); - } finally { - throw e; - } - } cleanupSubscription(subscription); - return value; - }, - complete: function complete(value){ - var subscription = this._s; - if(!subscriptionClosed(subscription)){ - var observer = subscription._o; - subscription._o = undefined; - try { - var m = getMethod(observer.complete); - value = m ? m.call(observer, value) : undefined; - } catch(e){ - try { - cleanupSubscription(subscription); - } finally { - throw e; - } - } cleanupSubscription(subscription); - return value; - } - } -}); - -var $Observable = function Observable(subscriber){ - anInstance(this, $Observable, 'Observable', '_f')._f = aFunction(subscriber); -}; - -redefineAll($Observable.prototype, { - subscribe: function subscribe(observer){ - return new Subscription(observer, this._f); - }, - forEach: function forEach(fn){ - var that = this; - return new (core.Promise || global.Promise)(function(resolve, reject){ - aFunction(fn); - var subscription = that.subscribe({ - next : function(value){ - try { - return fn(value); - } catch(e){ - reject(e); - subscription.unsubscribe(); - } - }, - error: reject, - complete: resolve - }); - }); - } -}); - -redefineAll($Observable, { - from: function from(x){ - var C = typeof this === 'function' ? this : $Observable; - var method = getMethod(anObject(x)[OBSERVABLE]); - if(method){ - var observable = anObject(method.call(x)); - return observable.constructor === C ? observable : new C(function(observer){ - return observable.subscribe(observer); - }); - } - return new C(function(observer){ - var done = false; - microtask(function(){ - if(!done){ - try { - if(forOf(x, false, function(it){ - observer.next(it); - if(done)return RETURN; - }) === RETURN)return; - } catch(e){ - if(done)throw e; - observer.error(e); - return; - } observer.complete(); - } - }); - return function(){ done = true; }; - }); - }, - of: function of(){ - for(var i = 0, l = arguments.length, items = Array(l); i < l;)items[i] = arguments[i++]; - return new (typeof this === 'function' ? this : $Observable)(function(observer){ - var done = false; - microtask(function(){ - if(!done){ - for(var i = 0; i < items.length; ++i){ - observer.next(items[i]); - if(done)return; - } observer.complete(); - } - }); - return function(){ done = true; }; - }); - } -}); - -hide($Observable.prototype, OBSERVABLE, function(){ return this; }); - -$export($export.G, {Observable: $Observable}); - -__webpack_require__(38)('Observable'); - -/***/ }), -/* 285 */ -/***/ (function(module, exports, __webpack_require__) { - -var metadata = __webpack_require__(26) - , anObject = __webpack_require__(1) - , toMetaKey = metadata.key - , ordinaryDefineOwnMetadata = metadata.set; - -metadata.exp({defineMetadata: function defineMetadata(metadataKey, metadataValue, target, targetKey){ - ordinaryDefineOwnMetadata(metadataKey, metadataValue, anObject(target), toMetaKey(targetKey)); -}}); - -/***/ }), -/* 286 */ -/***/ (function(module, exports, __webpack_require__) { - -var metadata = __webpack_require__(26) - , anObject = __webpack_require__(1) - , toMetaKey = metadata.key - , getOrCreateMetadataMap = metadata.map - , store = metadata.store; - -metadata.exp({deleteMetadata: function deleteMetadata(metadataKey, target /*, targetKey */){ - var targetKey = arguments.length < 3 ? undefined : toMetaKey(arguments[2]) - , metadataMap = getOrCreateMetadataMap(anObject(target), targetKey, false); - if(metadataMap === undefined || !metadataMap['delete'](metadataKey))return false; - if(metadataMap.size)return true; - var targetMetadata = store.get(target); - targetMetadata['delete'](targetKey); - return !!targetMetadata.size || store['delete'](target); -}}); - -/***/ }), -/* 287 */ -/***/ (function(module, exports, __webpack_require__) { - -var Set = __webpack_require__(115) - , from = __webpack_require__(91) - , metadata = __webpack_require__(26) - , anObject = __webpack_require__(1) - , getPrototypeOf = __webpack_require__(17) - , ordinaryOwnMetadataKeys = metadata.keys - , toMetaKey = metadata.key; - -var ordinaryMetadataKeys = function(O, P){ - var oKeys = ordinaryOwnMetadataKeys(O, P) - , parent = getPrototypeOf(O); - if(parent === null)return oKeys; - var pKeys = ordinaryMetadataKeys(parent, P); - return pKeys.length ? oKeys.length ? from(new Set(oKeys.concat(pKeys))) : pKeys : oKeys; -}; - -metadata.exp({getMetadataKeys: function getMetadataKeys(target /*, targetKey */){ - return ordinaryMetadataKeys(anObject(target), arguments.length < 2 ? undefined : toMetaKey(arguments[1])); -}}); - -/***/ }), -/* 288 */ -/***/ (function(module, exports, __webpack_require__) { - -var metadata = __webpack_require__(26) - , anObject = __webpack_require__(1) - , getPrototypeOf = __webpack_require__(17) - , ordinaryHasOwnMetadata = metadata.has - , ordinaryGetOwnMetadata = metadata.get - , toMetaKey = metadata.key; - -var ordinaryGetMetadata = function(MetadataKey, O, P){ - var hasOwn = ordinaryHasOwnMetadata(MetadataKey, O, P); - if(hasOwn)return ordinaryGetOwnMetadata(MetadataKey, O, P); - var parent = getPrototypeOf(O); - return parent !== null ? ordinaryGetMetadata(MetadataKey, parent, P) : undefined; -}; - -metadata.exp({getMetadata: function getMetadata(metadataKey, target /*, targetKey */){ - return ordinaryGetMetadata(metadataKey, anObject(target), arguments.length < 3 ? undefined : toMetaKey(arguments[2])); -}}); - -/***/ }), -/* 289 */ -/***/ (function(module, exports, __webpack_require__) { - -var metadata = __webpack_require__(26) - , anObject = __webpack_require__(1) - , ordinaryOwnMetadataKeys = metadata.keys - , toMetaKey = metadata.key; - -metadata.exp({getOwnMetadataKeys: function getOwnMetadataKeys(target /*, targetKey */){ - return ordinaryOwnMetadataKeys(anObject(target), arguments.length < 2 ? undefined : toMetaKey(arguments[1])); -}}); - -/***/ }), -/* 290 */ -/***/ (function(module, exports, __webpack_require__) { - -var metadata = __webpack_require__(26) - , anObject = __webpack_require__(1) - , ordinaryGetOwnMetadata = metadata.get - , toMetaKey = metadata.key; - -metadata.exp({getOwnMetadata: function getOwnMetadata(metadataKey, target /*, targetKey */){ - return ordinaryGetOwnMetadata(metadataKey, anObject(target) - , arguments.length < 3 ? undefined : toMetaKey(arguments[2])); -}}); - -/***/ }), -/* 291 */ -/***/ (function(module, exports, __webpack_require__) { - -var metadata = __webpack_require__(26) - , anObject = __webpack_require__(1) - , getPrototypeOf = __webpack_require__(17) - , ordinaryHasOwnMetadata = metadata.has - , toMetaKey = metadata.key; - -var ordinaryHasMetadata = function(MetadataKey, O, P){ - var hasOwn = ordinaryHasOwnMetadata(MetadataKey, O, P); - if(hasOwn)return true; - var parent = getPrototypeOf(O); - return parent !== null ? ordinaryHasMetadata(MetadataKey, parent, P) : false; -}; - -metadata.exp({hasMetadata: function hasMetadata(metadataKey, target /*, targetKey */){ - return ordinaryHasMetadata(metadataKey, anObject(target), arguments.length < 3 ? undefined : toMetaKey(arguments[2])); -}}); - -/***/ }), -/* 292 */ -/***/ (function(module, exports, __webpack_require__) { - -var metadata = __webpack_require__(26) - , anObject = __webpack_require__(1) - , ordinaryHasOwnMetadata = metadata.has - , toMetaKey = metadata.key; - -metadata.exp({hasOwnMetadata: function hasOwnMetadata(metadataKey, target /*, targetKey */){ - return ordinaryHasOwnMetadata(metadataKey, anObject(target) - , arguments.length < 3 ? undefined : toMetaKey(arguments[2])); -}}); - -/***/ }), -/* 293 */ -/***/ (function(module, exports, __webpack_require__) { - -var metadata = __webpack_require__(26) - , anObject = __webpack_require__(1) - , aFunction = __webpack_require__(11) - , toMetaKey = metadata.key - , ordinaryDefineOwnMetadata = metadata.set; - -metadata.exp({metadata: function metadata(metadataKey, metadataValue){ - return function decorator(target, targetKey){ - ordinaryDefineOwnMetadata( - metadataKey, metadataValue, - (targetKey !== undefined ? anObject : aFunction)(target), - toMetaKey(targetKey) - ); - }; -}}); - -/***/ }), -/* 294 */ -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__(0); - -$export($export.P + $export.R, 'Set', {toJSON: __webpack_require__(95)('Set')}); - -/***/ }), -/* 295 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// https://github.com/mathiasbynens/String.prototype.at -var $export = __webpack_require__(0) - , $at = __webpack_require__(79)(true); - -$export($export.P, 'String', { - at: function at(pos){ - return $at(this, pos); - } -}); - -/***/ }), -/* 296 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// https://tc39.github.io/String.prototype.matchAll/ -var $export = __webpack_require__(0) - , defined = __webpack_require__(19) - , toLength = __webpack_require__(8) - , isRegExp = __webpack_require__(56) - , getFlags = __webpack_require__(54) - , RegExpProto = RegExp.prototype; - -var $RegExpStringIterator = function(regexp, string){ - this._r = regexp; - this._s = string; -}; - -__webpack_require__(71)($RegExpStringIterator, 'RegExp String', function next(){ - var match = this._r.exec(this._s); - return {value: match, done: match === null}; -}); - -$export($export.P, 'String', { - matchAll: function matchAll(regexp){ - defined(this); - if(!isRegExp(regexp))throw TypeError(regexp + ' is not a regexp!'); - var S = String(this) - , flags = 'flags' in RegExpProto ? String(regexp.flags) : getFlags.call(regexp) - , rx = new RegExp(regexp.source, ~flags.indexOf('g') ? flags : 'g' + flags); - rx.lastIndex = toLength(regexp.lastIndex); - return new $RegExpStringIterator(rx, S); - } -}); - -/***/ }), -/* 297 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// https://github.com/tc39/proposal-string-pad-start-end -var $export = __webpack_require__(0) - , $pad = __webpack_require__(111); - -$export($export.P, 'String', { - padEnd: function padEnd(maxLength /*, fillString = ' ' */){ - return $pad(this, maxLength, arguments.length > 1 ? arguments[1] : undefined, false); - } -}); - -/***/ }), -/* 298 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// https://github.com/tc39/proposal-string-pad-start-end -var $export = __webpack_require__(0) - , $pad = __webpack_require__(111); - -$export($export.P, 'String', { - padStart: function padStart(maxLength /*, fillString = ' ' */){ - return $pad(this, maxLength, arguments.length > 1 ? arguments[1] : undefined, true); - } -}); - -/***/ }), -/* 299 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// https://github.com/sebmarkbage/ecmascript-string-left-right-trim -__webpack_require__(46)('trimLeft', function($trim){ - return function trimLeft(){ - return $trim(this, 1); - }; -}, 'trimStart'); - -/***/ }), -/* 300 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -// https://github.com/sebmarkbage/ecmascript-string-left-right-trim -__webpack_require__(46)('trimRight', function($trim){ - return function trimRight(){ - return $trim(this, 2); - }; -}, 'trimEnd'); - -/***/ }), -/* 301 */ -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__(85)('asyncIterator'); - -/***/ }), -/* 302 */ -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__(85)('observable'); - -/***/ }), -/* 303 */ -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/ljharb/proposal-global -var $export = __webpack_require__(0); - -$export($export.S, 'System', {global: __webpack_require__(2)}); - -/***/ }), -/* 304 */ -/***/ (function(module, exports, __webpack_require__) { - -var $iterators = __webpack_require__(87) - , redefine = __webpack_require__(13) - , global = __webpack_require__(2) - , hide = __webpack_require__(12) - , Iterators = __webpack_require__(44) - , wks = __webpack_require__(5) - , ITERATOR = wks('iterator') - , TO_STRING_TAG = wks('toStringTag') - , ArrayValues = Iterators.Array; - -for(var collections = ['NodeList', 'DOMTokenList', 'MediaList', 'StyleSheetList', 'CSSRuleList'], i = 0; i < 5; i++){ - var NAME = collections[i] - , Collection = global[NAME] - , proto = Collection && Collection.prototype - , key; - if(proto){ - if(!proto[ITERATOR])hide(proto, ITERATOR, ArrayValues); - if(!proto[TO_STRING_TAG])hide(proto, TO_STRING_TAG, NAME); - Iterators[NAME] = ArrayValues; - for(key in $iterators)if(!proto[key])redefine(proto, key, $iterators[key], true); - } -} - -/***/ }), -/* 305 */ -/***/ (function(module, exports, __webpack_require__) { - -var $export = __webpack_require__(0) - , $task = __webpack_require__(83); -$export($export.G + $export.B, { - setImmediate: $task.set, - clearImmediate: $task.clear -}); - -/***/ }), -/* 306 */ -/***/ (function(module, exports, __webpack_require__) { - -// ie9- setTimeout & setInterval additional parameters fix -var global = __webpack_require__(2) - , $export = __webpack_require__(0) - , invoke = __webpack_require__(55) - , partial = __webpack_require__(133) - , navigator = global.navigator - , MSIE = !!navigator && /MSIE .\./.test(navigator.userAgent); // <- dirty ie9- check -var wrap = function(set){ - return MSIE ? function(fn, time /*, ...args */){ - return set(invoke( - partial, - [].slice.call(arguments, 2), - typeof fn == 'function' ? fn : Function(fn) - ), time); - } : set; -}; -$export($export.G + $export.B + $export.F * MSIE, { - setTimeout: wrap(global.setTimeout), - setInterval: wrap(global.setInterval) -}); - -/***/ }), -/* 307 */ -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__(256); -__webpack_require__(195); -__webpack_require__(197); -__webpack_require__(196); -__webpack_require__(199); -__webpack_require__(201); -__webpack_require__(206); -__webpack_require__(200); -__webpack_require__(198); -__webpack_require__(208); -__webpack_require__(207); -__webpack_require__(203); -__webpack_require__(204); -__webpack_require__(202); -__webpack_require__(194); -__webpack_require__(205); -__webpack_require__(209); -__webpack_require__(210); -__webpack_require__(162); -__webpack_require__(164); -__webpack_require__(163); -__webpack_require__(212); -__webpack_require__(211); -__webpack_require__(182); -__webpack_require__(192); -__webpack_require__(193); -__webpack_require__(183); -__webpack_require__(184); -__webpack_require__(185); -__webpack_require__(186); -__webpack_require__(187); -__webpack_require__(188); -__webpack_require__(189); -__webpack_require__(190); -__webpack_require__(191); -__webpack_require__(165); -__webpack_require__(166); -__webpack_require__(167); -__webpack_require__(168); -__webpack_require__(169); -__webpack_require__(170); -__webpack_require__(171); -__webpack_require__(172); -__webpack_require__(173); -__webpack_require__(174); -__webpack_require__(175); -__webpack_require__(176); -__webpack_require__(177); -__webpack_require__(178); -__webpack_require__(179); -__webpack_require__(180); -__webpack_require__(181); -__webpack_require__(243); -__webpack_require__(248); -__webpack_require__(255); -__webpack_require__(246); -__webpack_require__(238); -__webpack_require__(239); -__webpack_require__(244); -__webpack_require__(249); -__webpack_require__(251); -__webpack_require__(234); -__webpack_require__(235); -__webpack_require__(236); -__webpack_require__(237); -__webpack_require__(240); -__webpack_require__(241); -__webpack_require__(242); -__webpack_require__(245); -__webpack_require__(247); -__webpack_require__(250); -__webpack_require__(252); -__webpack_require__(253); -__webpack_require__(254); -__webpack_require__(157); -__webpack_require__(159); -__webpack_require__(158); -__webpack_require__(161); -__webpack_require__(160); -__webpack_require__(146); -__webpack_require__(144); -__webpack_require__(150); -__webpack_require__(147); -__webpack_require__(153); -__webpack_require__(155); -__webpack_require__(143); -__webpack_require__(149); -__webpack_require__(140); -__webpack_require__(154); -__webpack_require__(138); -__webpack_require__(152); -__webpack_require__(151); -__webpack_require__(145); -__webpack_require__(148); -__webpack_require__(137); -__webpack_require__(139); -__webpack_require__(142); -__webpack_require__(141); -__webpack_require__(156); -__webpack_require__(87); -__webpack_require__(228); -__webpack_require__(233); -__webpack_require__(114); -__webpack_require__(229); -__webpack_require__(230); -__webpack_require__(231); -__webpack_require__(232); -__webpack_require__(213); -__webpack_require__(113); -__webpack_require__(115); -__webpack_require__(116); -__webpack_require__(268); -__webpack_require__(257); -__webpack_require__(258); -__webpack_require__(263); -__webpack_require__(266); -__webpack_require__(267); -__webpack_require__(261); -__webpack_require__(264); -__webpack_require__(262); -__webpack_require__(265); -__webpack_require__(259); -__webpack_require__(260); -__webpack_require__(214); -__webpack_require__(215); -__webpack_require__(216); -__webpack_require__(217); -__webpack_require__(218); -__webpack_require__(221); -__webpack_require__(219); -__webpack_require__(220); -__webpack_require__(222); -__webpack_require__(223); -__webpack_require__(224); -__webpack_require__(225); -__webpack_require__(227); -__webpack_require__(226); -__webpack_require__(269); -__webpack_require__(295); -__webpack_require__(298); -__webpack_require__(297); -__webpack_require__(299); -__webpack_require__(300); -__webpack_require__(296); -__webpack_require__(301); -__webpack_require__(302); -__webpack_require__(280); -__webpack_require__(283); -__webpack_require__(279); -__webpack_require__(277); -__webpack_require__(278); -__webpack_require__(281); -__webpack_require__(282); -__webpack_require__(272); -__webpack_require__(294); -__webpack_require__(303); -__webpack_require__(271); -__webpack_require__(273); -__webpack_require__(275); -__webpack_require__(274); -__webpack_require__(276); -__webpack_require__(285); -__webpack_require__(286); -__webpack_require__(288); -__webpack_require__(287); -__webpack_require__(290); -__webpack_require__(289); -__webpack_require__(291); -__webpack_require__(292); -__webpack_require__(293); -__webpack_require__(270); -__webpack_require__(284); -__webpack_require__(306); -__webpack_require__(305); -__webpack_require__(304); -module.exports = __webpack_require__(24); - -/***/ }), -/* 308 */ -/***/ (function(module, exports, __webpack_require__) { - -exports = module.exports = __webpack_require__(309)(undefined); -// imports - - -// module -exports.push([module.i, "@-webkit-keyframes sb-fade-in {\n 0% {\n opacity: 0; }\n 100% {\n opacity: 1; } }\n\n@-moz-keyframes sb-fade-in {\n 0% {\n opacity: 0; }\n 100% {\n opacity: 1; } }\n\n@-o-keyframes sb-fade-in {\n 0% {\n opacity: 0; }\n 100% {\n opacity: 1; } }\n\n@-ms-keyframes sb-fade-in {\n 0% {\n opacity: 0; }\n 100% {\n opacity: 1; } }\n\n@keyframes sb-fade-in {\n 0% {\n opacity: 0; }\n 100% {\n opacity: 1; } }\n\n@-webkit-keyframes sb-fade-out {\n 0% {\n opacity: 1; }\n 100% {\n opacity: 0; } }\n\n@-moz-keyframes sb-fade-out {\n 0% {\n opacity: 1; }\n 100% {\n opacity: 0; } }\n\n@-o-keyframes sb-fade-out {\n 0% {\n opacity: 1; }\n 100% {\n opacity: 0; } }\n\n@-ms-keyframes sb-fade-out {\n 0% {\n opacity: 1; }\n 100% {\n opacity: 0; } }\n\n@keyframes sb-fade-out {\n 0% {\n opacity: 1; }\n 100% {\n opacity: 0; } }\n\n@-webkit-keyframes sb-loader {\n 0%, 80%, 100% {\n -webkit-transform: scale(0);\n -moz-transform: scale(0);\n -ms-transform: scale(0);\n -o-transform: scale(0);\n transform: scale(0); }\n 40% {\n -webkit-transform: scale(1);\n -moz-transform: scale(1);\n -ms-transform: scale(1);\n -o-transform: scale(1);\n transform: scale(1); } }\n\n@-moz-keyframes sb-loader {\n 0%, 80%, 100% {\n -webkit-transform: scale(0);\n -moz-transform: scale(0);\n -ms-transform: scale(0);\n -o-transform: scale(0);\n transform: scale(0); }\n 40% {\n -webkit-transform: scale(1);\n -moz-transform: scale(1);\n -ms-transform: scale(1);\n -o-transform: scale(1);\n transform: scale(1); } }\n\n@-o-keyframes sb-loader {\n 0%, 80%, 100% {\n -webkit-transform: scale(0);\n -moz-transform: scale(0);\n -ms-transform: scale(0);\n -o-transform: scale(0);\n transform: scale(0); }\n 40% {\n -webkit-transform: scale(1);\n -moz-transform: scale(1);\n -ms-transform: scale(1);\n -o-transform: scale(1);\n transform: scale(1); } }\n\n@-ms-keyframes sb-loader {\n 0%, 80%, 100% {\n -webkit-transform: scale(0);\n -moz-transform: scale(0);\n -ms-transform: scale(0);\n -o-transform: scale(0);\n transform: scale(0); }\n 40% {\n -webkit-transform: scale(1);\n -moz-transform: scale(1);\n -ms-transform: scale(1);\n -o-transform: scale(1);\n transform: scale(1); } }\n\n@keyframes sb-loader {\n 0%, 80%, 100% {\n -webkit-transform: scale(0);\n -moz-transform: scale(0);\n -ms-transform: scale(0);\n -o-transform: scale(0);\n transform: scale(0); }\n 40% {\n -webkit-transform: scale(1);\n -moz-transform: scale(1);\n -ms-transform: scale(1);\n -o-transform: scale(1);\n transform: scale(1); } }\n\n#sb_widget {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n z-index: 99990;\n width: 60px;\n height: 60px;\n position: fixed;\n bottom: 0;\n right: 20px;\n font-family: \"Lato\";\n font-weight: 400;\n -webkit-font-smoothing: antialiased; }\n #sb_widget .sb-fade-in {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n -webkit-animation: sb-fade-in 0.5s;\n -moz-animation: sb-fade-in 0.5s;\n -o-animation: sb-fade-in 0.5s;\n -ms-animation: sb-fade-in 0.5s;\n animation: sb-fade-in 0.5s; }\n #sb_widget .sb-fade-out {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n -webkit-animation: sb-fade-out 0.5s;\n -moz-animation: sb-fade-out 0.5s;\n -o-animation: sb-fade-out 0.5s;\n -ms-animation: sb-fade-out 0.5s;\n animation: sb-fade-out 0.5s; }\n #sb_widget .sb-spinner, #sb_widget .chat-section .content .sb-spinner {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: 100%;\n text-align: center; }\n #sb_widget .sb-spinner div, #sb_widget .chat-section .content .sb-spinner div {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: inline-block;\n width: 12px;\n height: 12px;\n background-color: #A5B3CD;\n border-radius: 50%;\n -webkit-border-radius: 50%;\n -moz-border-radius: 50%;\n -ms-border-radius: 50%;\n -o-border-radius: 50%;\n -webkit-animation: sb-loader 1.4s infinite ease-in-out both;\n -moz-animation: sb-loader 1.4s infinite ease-in-out both;\n -o-animation: sb-loader 1.4s infinite ease-in-out both;\n -ms-animation: sb-loader 1.4s infinite ease-in-out both;\n animation: sb-loader 1.4s infinite ease-in-out both; }\n #sb_widget .sb-spinner :nth-child(1), #sb_widget .chat-section .content .sb-spinner :nth-child(1) {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n -webkit-animation-delay: -0.32s;\n -moz-animation-delay: -0.32s;\n -o-animation-delay: -0.32s;\n -ms-animation-delay: -0.32s;\n animation-delay: -0.32s; }\n #sb_widget .sb-spinner :nth-child(2), #sb_widget .chat-section .content .sb-spinner :nth-child(2) {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n margin: 0 6px;\n -webkit-animation-delay: -0.16s;\n -moz-animation-delay: -0.16s;\n -o-animation-delay: -0.16s;\n -ms-animation-delay: -0.16s;\n animation-delay: -0.16s; }\n #sb_widget .ic-login {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/icon-open-nonmember.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .ic-connected {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/icon-open-member.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .ic-minimize {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-minimize-default.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .ic-minimize:hover {\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-minimize-over.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .ic-option {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-option-default.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .ic-option:hover {\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-option-over.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .ic-option.active {\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-option-over.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .ic-new-chat {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-new-chat-default.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .ic-new-chat:hover {\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-new-chat-over.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .ic-close {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-close-default.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .ic-close:hover {\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-close-over.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .ic-close.active {\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-close-select.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .ic-members {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-friend-list-default.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .ic-members:hover {\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-friend-list-over.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .ic-members.active {\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-friend-list-select.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .ic-invite {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-friend-add-default.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .ic-invite:hover {\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-friend-add-over.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .ic-invite.active {\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-friend-add-select.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .ic-leave {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-leave-chat-normal.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .ic-leave:hover {\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-leave-chat-over.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .tooltip, #sb_widget .channel-board .board-top .btn:hover > .tooltip, #sb_widget .channel-board .board-top .btn .tooltip, #sb_widget .chat-section .top .btn:hover > .tooltip, #sb_widget .chat-section .top .btn.ic-leave .tooltip, #sb_widget .chat-section .top .btn.ic-members .tooltip, #sb_widget .chat-section .top .btn.ic-invite .tooltip {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: none;\n background-color: #000000;\n text-align: center;\n z-index: 1;\n font-size: 12px;\n color: #FFFFFF;\n padding: 0 12px;\n height: 32px;\n line-height: 32px; }\n #sb_widget .tooltip::after, #sb_widget .channel-board .board-top .btn:hover > .tooltip::after, #sb_widget .channel-board .board-top .btn .tooltip::after, #sb_widget .chat-section .top .btn:hover > .tooltip::after, #sb_widget .chat-section .top .btn.ic-leave .tooltip::after, #sb_widget .chat-section .top .btn.ic-members .tooltip::after, #sb_widget .chat-section .top .btn.ic-invite .tooltip::after {\n content: ' ';\n position: absolute;\n top: 100%;\n left: 50%;\n margin-left: -5px;\n border-width: 5px;\n border-style: solid;\n border-color: #000000 transparent transparent transparent; }\n #sb_widget .widget {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n z-index: 99991;\n position: absolute;\n right: 0;\n bottom: 20px;\n width: 60px;\n height: 60px;\n cursor: pointer;\n border-radius: 50%;\n -webkit-border-radius: 50%;\n -moz-border-radius: 50%;\n -ms-border-radius: 50%;\n -o-border-radius: 50%;\n -webkit-box-shadow: 0 1px 6px rgba(0, 0, 0, 0.06), 0 2px 32px rgba(0, 0, 0, 0.16);\n -moz-box-shadow: 0 1px 6px rgba(0, 0, 0, 0.06), 0 2px 32px rgba(0, 0, 0, 0.16);\n box-shadow: 0 1px 6px rgba(0, 0, 0, 0.06), 0 2px 32px rgba(0, 0, 0, 0.16);\n background-color: #896BF5; }\n #sb_widget .widget:hover {\n background-color: #775AE0;\n -webkit-box-shadow: 0 1px 9px rgba(0, 0, 0, 0.28), 0 2px 32px rgba(0, 0, 0, 0.16);\n -moz-box-shadow: 0 1px 9px rgba(0, 0, 0, 0.28), 0 2px 32px rgba(0, 0, 0, 0.16);\n box-shadow: 0 1px 9px rgba(0, 0, 0, 0.28), 0 2px 32px rgba(0, 0, 0, 0.16); }\n #sb_widget .widget .notification {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: none;\n position: absolute;\n top: 0;\n right: 0;\n width: 18px;\n height: 18px;\n background-color: #FB6094;\n color: #FFFFFF;\n font-weight: 700;\n font-size: 12px;\n line-height: 18px;\n text-align: center;\n border-radius: 50%;\n -webkit-border-radius: 50%;\n -moz-border-radius: 50%;\n -ms-border-radius: 50%;\n -o-border-radius: 50%;\n -webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.28);\n -moz-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.28);\n box-shadow: 0 1px 5px rgba(0, 0, 0, 0.28); }\n #sb_widget .sb-common-btn, #sb_widget .channel-board .content .login-btn, #sb_widget .channel-board .content.channel-list ul .empty-item > .new-chat-btn, #sb_widget .chat-section .chat-board .leave-popup > div .leave-btn, #sb_widget .chat-section .chat-board .leave-popup > div .cancel-btn, #sb_widget .chat-section .content .content-bottom .new-chat-btn, #sb_widget .popup .popup-bottom .invite-btn {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n padding: 0 16px;\n border: 1px solid #38B349;\n background-color: #3FCC52;\n color: #FFFFFF;\n cursor: pointer;\n border-radius: 3px;\n -webkit-border-radius: 3px;\n -moz-border-radius: 3px;\n -ms-border-radius: 3px;\n -o-border-radius: 3px;\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 1px rgba(255, 255, 255, 0.75);\n -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 1px rgba(255, 255, 255, 0.75);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 1px rgba(255, 255, 255, 0.75); }\n #sb_widget .sb-common-btn:hover, #sb_widget .channel-board .content .login-btn:hover, #sb_widget .channel-board .content.channel-list ul .empty-item > .new-chat-btn:hover, #sb_widget .chat-section .chat-board .leave-popup > div .leave-btn:hover, #sb_widget .chat-section .chat-board .leave-popup > div .cancel-btn:hover, #sb_widget .chat-section .content .content-bottom .new-chat-btn:hover, #sb_widget .popup .popup-bottom .invite-btn:hover {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), 0 1px rgba(255, 255, 255, 0.75);\n -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), 0 1px rgba(255, 255, 255, 0.75);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), 0 1px rgba(255, 255, 255, 0.75); }\n #sb_widget .sb-common-btn.disabled, #sb_widget .channel-board .content .disabled.login-btn, #sb_widget .channel-board .content.channel-list ul .empty-item > .disabled.new-chat-btn, #sb_widget .chat-section .chat-board .leave-popup > div .disabled.leave-btn, #sb_widget .chat-section .chat-board .leave-popup > div .disabled.cancel-btn, #sb_widget .chat-section .content .content-bottom .disabled.new-chat-btn, #sb_widget .popup .popup-bottom .disabled.invite-btn {\n background-color: #98DC99;\n border: 1px solid #95D296; }\n #sb_widget .sb-common-btn.disabled:hover, #sb_widget .channel-board .content .disabled.login-btn:hover, #sb_widget .channel-board .content.channel-list ul .empty-item > .disabled.new-chat-btn:hover, #sb_widget .chat-section .chat-board .leave-popup > div .disabled.leave-btn:hover, #sb_widget .chat-section .chat-board .leave-popup > div .disabled.cancel-btn:hover, #sb_widget .chat-section .content .content-bottom .disabled.new-chat-btn:hover, #sb_widget .popup .popup-bottom .disabled.invite-btn:hover {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 1px rgba(255, 255, 255, 0.75);\n -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 1px rgba(255, 255, 255, 0.75);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 1px rgba(255, 255, 255, 0.75); }\n #sb_widget .channel-board {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: none;\n z-index: 99992;\n position: absolute;\n bottom: 0;\n right: 0;\n width: 280px;\n height: 462px;\n -webkit-box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3);\n -moz-box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3);\n box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3); }\n #sb_widget .channel-board .board-top {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: calc(100% - 24px);\n height: 36px;\n background-color: #896BF5;\n padding: 0 12px;\n border-bottom: 1px solid #795FDC; }\n #sb_widget .channel-board .board-top .title {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: inline-block;\n float: left;\n font-size: 16px;\n color: #EBE6FF;\n letter-spacing: 0.85px;\n line-height: 36px; }\n #sb_widget .channel-board .board-top .btn {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: inline-block;\n float: right;\n position: relative;\n top: 50%;\n width: 24px;\n height: 26px;\n cursor: pointer;\n -webkit-transform: translate(0, -50%);\n -moz-transform: translate(0, -50%);\n -ms-transform: translate(0, -50%);\n -o-transform: translate(0, -50%);\n transform: translate(0, -50%); }\n #sb_widget .channel-board .board-top .btn:hover > .tooltip, #sb_widget .channel-board .board-top .chat-section .top .btn:hover > .tooltip, #sb_widget .channel-board .board-top .chat-section .top .btn.ic-leave .btn:hover > .tooltip, #sb_widget .channel-board .board-top .chat-section .top .btn.ic-members .btn:hover > .tooltip, #sb_widget .channel-board .board-top .chat-section .top .btn.ic-invite .btn:hover > .tooltip {\n font-size: 12px;\n display: block; }\n #sb_widget .channel-board .board-top .btn:hover > .tooltip, #sb_widget .channel-board .board-top .btn .tooltip, #sb_widget .channel-board .board-top .chat-section .top .btn:hover > .tooltip, #sb_widget .channel-board .board-top .chat-section .top .btn.ic-leave .tooltip, #sb_widget .chat-section .top .channel-board .board-top .btn.ic-leave .tooltip, #sb_widget .channel-board .board-top .chat-section .top .btn.ic-members .tooltip, #sb_widget .chat-section .top .channel-board .board-top .btn.ic-members .tooltip, #sb_widget .channel-board .board-top .chat-section .top .btn.ic-invite .tooltip, #sb_widget .chat-section .top .channel-board .board-top .btn.ic-invite .tooltip {\n width: 74px;\n position: absolute;\n top: -37px;\n left: -37px; }\n #sb_widget .channel-board .board-top .btn .option-menu {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: none;\n position: absolute;\n top: 25px;\n right: -35px;\n width: 140px;\n height: 42px;\n background-color: transparent;\n cursor: pointer; }\n #sb_widget .channel-board .board-top .btn .option-menu .option-content {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n position: absolute;\n bottom: 0;\n width: calc(100% - 32px);\n height: 32px;\n background-color: #FFFFFF;\n font-size: 13px;\n color: #485874;\n line-height: 32px;\n padding: 0 16px;\n border-radius: 3px;\n -webkit-border-radius: 3px;\n -moz-border-radius: 3px;\n -ms-border-radius: 3px;\n -o-border-radius: 3px;\n -webkit-box-shadow: 1px 1px 14px 3px rgba(0, 0, 0, 0.3);\n -moz-box-shadow: 1px 1px 14px 3px rgba(0, 0, 0, 0.3);\n box-shadow: 1px 1px 14px 3px rgba(0, 0, 0, 0.3); }\n #sb_widget .channel-board .board-top .btn .option-menu .option-content::before {\n content: ' ';\n position: absolute;\n bottom: 100%;\n left: calc(50% + 21px);\n margin-left: -5px;\n border-width: 7px;\n border-style: solid;\n border-color: transparent transparent #FFFFFF transparent; }\n #sb_widget .channel-board .content {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n height: 426px;\n background-color: #FFFFFF; }\n #sb_widget .channel-board .content .user-id {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: 100%;\n padding-top: 30px; }\n #sb_widget .channel-board .content .nickname {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: 100%;\n padding-top: 12px; }\n #sb_widget .channel-board .content .title {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n font-size: 11px;\n color: #67769A;\n padding-bottom: 6px; }\n #sb_widget .channel-board .content .input {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: calc(98% - 16px);\n height: 32px;\n border: 1px solid #E2E7EB;\n background-color: #F8F9FA;\n font-size: 13px;\n color: #3A414D;\n padding: 0 8px;\n border-radius: 3px;\n -webkit-border-radius: 3px;\n -moz-border-radius: 3px;\n -ms-border-radius: 3px;\n -o-border-radius: 3px; }\n #sb_widget .channel-board .content .input:focus {\n outline: none;\n border: 1px solid #7b5fd9;\n -webkit-box-shadow: 0 0 4px #BDB0FF;\n -moz-box-shadow: 0 0 4px #BDB0FF;\n box-shadow: 0 0 4px #BDB0FF; }\n #sb_widget .channel-board .content .login-btn {\n display: inline-block;\n position: absolute;\n left: 50%;\n margin-top: 20px;\n height: 32px;\n width: calc(98px - 32px);\n text-align: center;\n line-height: 32px;\n font-size: 14px;\n -webkit-transform: translate(-50%, 0);\n -moz-transform: translate(-50%, 0);\n -ms-transform: translate(-50%, 0);\n -o-transform: translate(-50%, 0);\n transform: translate(-50%, 0); }\n #sb_widget .channel-board .content .login-btn .sb-spinner {\n margin-top: 7px; }\n #sb_widget .channel-board .content .login-btn .sb-spinner div {\n width: 8px;\n height: 8px;\n margin-top: 4px;\n background-color: #35A300; }\n #sb_widget .channel-board .content .login-btn .sb-spinner :nth-child(2) {\n margin: 0 4px; }\n #sb_widget .channel-board .content.login-form {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: calc(100% - 24px);\n height: calc(100% - 37px);\n padding: 0 12px; }\n #sb_widget .channel-board .content.channel-list {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n overflow-y: scroll;\n overflow-x: hidden;\n width: 100%;\n height: calc(100% - 37px); }\n #sb_widget .channel-board .content.channel-list ul {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: 100%;\n margin: 0;\n padding: 0;\n list-style-type: none; }\n #sb_widget .channel-board .content.channel-list ul li {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: calc(100% - 24px);\n height: 48px;\n padding: 0 12px;\n background-color: #FFFFFF;\n cursor: pointer; }\n #sb_widget .channel-board .content.channel-list ul li:hover {\n background-color: #F5F8FA; }\n #sb_widget .channel-board .content.channel-list ul li:hover .content {\n background-color: #F5F8FA; }\n #sb_widget .channel-board .content.channel-list ul li .item {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: 100%;\n height: calc(100% - 12px - 1px);\n padding: 6px 0;\n border-bottom: 1px solid #E5E5E5; }\n #sb_widget .channel-board .content.channel-list ul .image {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n float: left;\n width: 36px;\n height: 100%;\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/thumnail-channel-01.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .channel-board .content.channel-list ul .content {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n float: right;\n width: calc(100% - 36px - 8px);\n height: 100%;\n margin-left: 8px; }\n #sb_widget .channel-board .content.channel-list ul .content-top {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: 100%;\n height: 50%; }\n #sb_widget .channel-board .content.channel-list ul .content-top .title {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n padding: 0;\n float: left;\n width: 125px;\n height: 18px;\n font-size: 14px;\n color: #444444;\n line-height: 18px;\n overflow: hidden;\n -ms-text-overflow: ellipsis;\n text-overflow: ellipsis;\n white-space: nowrap; }\n #sb_widget .channel-board .content.channel-list ul .content-top time {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n float: right;\n font-size: 12px;\n line-height: 18px;\n color: #A5B3CD; }\n #sb_widget .channel-board .content.channel-list ul .content-bottom {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: 100%;\n height: 50%; }\n #sb_widget .channel-board .content.channel-list ul .content-bottom .last-message {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n float: left;\n width: 170px;\n height: 18px;\n font-size: 13px;\n color: #A5B3CD;\n line-height: 18px;\n overflow: hidden;\n -ms-text-overflow: ellipsis;\n text-overflow: ellipsis;\n white-space: nowrap; }\n #sb_widget .channel-board .content.channel-list ul .content-bottom span {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: none;\n float: right;\n width: 18px;\n height: 18px;\n background-color: #FB6094;\n font-weight: 700;\n font-size: 12px;\n color: #FFFFFF;\n line-height: 18px;\n text-align: center;\n border-radius: 50%;\n -webkit-border-radius: 50%;\n -moz-border-radius: 50%;\n -ms-border-radius: 50%;\n -o-border-radius: 50%; }\n #sb_widget .channel-board .content.channel-list ul .empty-item {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n text-align: center; }\n #sb_widget .channel-board .content.channel-list ul .empty-item > .title {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n margin: 130px 0 16px 0;\n font-size: 14px;\n color: #67769A; }\n #sb_widget .channel-board .content.channel-list ul .empty-item > .new-chat-btn {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: block;\n margin: 0 auto;\n width: 48px;\n height: 30px;\n line-height: 30px;\n padding: 0 16px; }\n #sb_widget .channel-board .content.channel-list .sb-spinner {\n position: relative;\n top: calc(426px / 2);\n -webkit-transform: translate(0, -50%);\n -moz-transform: translate(0, -50%);\n -ms-transform: translate(0, -50%);\n -o-transform: translate(0, -50%);\n transform: translate(0, -50%); }\n #sb_widget .channel-board .content.channel-list .sb-spinner div {\n width: 12px;\n height: 12px;\n margin-top: 6px; }\n #sb_widget .channel-board .content.channel-list .sb-spinner :nth-child(2) {\n margin: 0 6px; }\n #sb_widget .chat-section {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n z-index: 99992;\n position: absolute;\n right: 60px;\n bottom: 0;\n width: auto;\n max-height: 520px; }\n #sb_widget .chat-section .chat-board {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n margin-top: 40px;\n float: right;\n width: 280px;\n height: 426px;\n margin-right: 20px;\n -webkit-box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3);\n -moz-box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3);\n box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3); }\n #sb_widget .chat-section .chat-board .leave-popup {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: 280px;\n height: 100%;\n position: absolute;\n background-color: rgba(255, 255, 255, 0.9);\n z-index: 1; }\n #sb_widget .chat-section .chat-board .leave-popup > .popup-top {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n margin-top: 130px;\n text-align: center;\n color: #67769A; }\n #sb_widget .chat-section .chat-board .leave-popup > div {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n margin-top: 16px;\n text-align: center; }\n #sb_widget .chat-section .chat-board .leave-popup > div .leave-btn {\n display: inline-block;\n padding: 0 8px;\n width: 52px;\n height: 32px;\n line-height: 32px; }\n #sb_widget .chat-section .chat-board .leave-popup > div .leave-btn .sb-spinner {\n line-height: 32px; }\n #sb_widget .chat-section .chat-board .leave-popup > div .leave-btn .sb-spinner div {\n width: 8px;\n height: 8px;\n margin-top: 4px;\n background-color: #35A300; }\n #sb_widget .chat-section .chat-board .leave-popup > div .leave-btn .sb-spinner :nth-child(2) {\n margin: 0 4px; }\n #sb_widget .chat-section .chat-board .leave-popup > div .leave-btn.disabled {\n cursor: default; }\n #sb_widget .chat-section .chat-board .leave-popup > div .cancel-btn {\n background-color: #F0F0F5;\n border-color: #E2E7EB;\n color: #67769A;\n margin-left: 8px;\n display: inline-block;\n padding: 0 8px;\n width: 52px;\n height: 32px;\n line-height: 32px; }\n #sb_widget .chat-section .top {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: calc(100% - 24px);\n height: 35px;\n padding: 0 12px;\n background-color: #F3F5F7;\n border-bottom: 1px solid #E5E5E5;\n -webkit-box-shadow: 0 1px 1px -2px rgba(0, 0, 0, 0.2);\n -moz-box-shadow: 0 1px 1px -2px rgba(0, 0, 0, 0.2);\n box-shadow: 0 1px 1px -2px rgba(0, 0, 0, 0.2); }\n #sb_widget .chat-section .top .title {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n float: left;\n max-width: 123px;\n font-size: 13px;\n color: #444444;\n line-height: 35px;\n overflow: hidden;\n -ms-text-overflow: ellipsis;\n text-overflow: ellipsis;\n white-space: nowrap; }\n #sb_widget .chat-section .top .count {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n float: left;\n width: 16px;\n height: 16px;\n margin-left: 8px;\n background-color: #D5D7D9;\n font-weight: 700;\n font-size: 10px;\n color: #67769A;\n text-align: center;\n line-height: 16px;\n position: relative;\n top: 50%;\n -webkit-transform: translate(0, -50%);\n -moz-transform: translate(0, -50%);\n -ms-transform: translate(0, -50%);\n -o-transform: translate(0, -50%);\n transform: translate(0, -50%); }\n #sb_widget .chat-section .top .btn {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n float: right;\n width: 24px;\n height: 26px;\n position: relative;\n top: 50%;\n cursor: pointer;\n -webkit-transform: translate(0, -50%);\n -moz-transform: translate(0, -50%);\n -ms-transform: translate(0, -50%);\n -o-transform: translate(0, -50%);\n transform: translate(0, -50%); }\n #sb_widget .chat-section .top .channel-board .board-top .btn:hover > .tooltip, #sb_widget .chat-section .top .btn:hover > .tooltip, #sb_widget .chat-section .top .btn.ic-leave .btn:hover > .tooltip, #sb_widget .chat-section .top .btn.ic-members .btn:hover > .tooltip, #sb_widget .chat-section .top .btn.ic-invite .btn:hover > .tooltip {\n display: block; }\n #sb_widget .chat-section .top .btn.ic-leave {\n margin-right: 3px; }\n #sb_widget .chat-section .top .btn.ic-leave .tooltip {\n width: 78px;\n position: absolute;\n top: -37px;\n left: -39px; }\n #sb_widget .chat-section .top .btn.ic-members {\n margin: 0 3px; }\n #sb_widget .chat-section .top .btn.ic-members .tooltip {\n width: 74px;\n position: absolute;\n top: -37px;\n left: -37px; }\n #sb_widget .chat-section .top .btn.ic-invite .tooltip {\n width: 78px;\n position: absolute;\n top: -37px;\n left: -39px; }\n #sb_widget .chat-section .content {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: 100%;\n height: calc(100% - 36px - 1px);\n background-color: #FFFFFF; }\n #sb_widget .chat-section .content .sb-spinner {\n position: relative;\n top: 50%;\n -webkit-transform: translate(0, -50%);\n -moz-transform: translate(0, -50%);\n -ms-transform: translate(0, -50%);\n -o-transform: translate(0, -50%);\n transform: translate(0, -50%); }\n #sb_widget .chat-section .content .user-content {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: 100%;\n height: calc(100% - 64px);\n background-color: #FFFFFF;\n overflow-y: scroll;\n overflow-x: hidden; }\n #sb_widget .chat-section .content .user-content ul {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: 100%;\n margin: 0;\n padding: 0;\n list-style-type: none; }\n #sb_widget .chat-section .content .user-content ul li {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: calc(100% - 24px);\n height: 44px;\n padding: 0 12px;\n cursor: pointer; }\n #sb_widget .chat-section .content .user-content ul li:hover {\n background-color: #F5F8FA; }\n #sb_widget .chat-section .content .user-content .user-item {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: 100%;\n height: calc(100% - 12px - 1px);\n padding: 6px 0;\n border-bottom: 1px solid #E5E5E5; }\n #sb_widget .chat-section .content .user-content .user-item .user-select {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n position: relative;\n top: 50%;\n float: left;\n width: 16px;\n height: 16px;\n -webkit-transform: translate(0, -50%);\n -moz-transform: translate(0, -50%);\n -ms-transform: translate(0, -50%);\n -o-transform: translate(0, -50%);\n transform: translate(0, -50%);\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-check-off.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .chat-section .content .user-content .user-item .user-select.active {\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-check-on.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .chat-section .content .user-content .user-item .image {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n float: left;\n width: 31px;\n height: 31px;\n margin: 0 8px;\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/thumnail-member-01.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .chat-section .content .user-content .user-item .nickname {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n float: left;\n font-size: 13px;\n color: #67769A;\n line-height: 31px;\n max-width: 70%;\n overflow: hidden;\n -ms-text-overflow: ellipsis;\n text-overflow: ellipsis;\n white-space: nowrap; }\n #sb_widget .chat-section .content .content-bottom {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: calc(100% - 24px);\n height: calc(52px - 24px);\n padding: 12px;\n background-color: #F3F5F7;\n text-align: center;\n -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);\n -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);\n box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); }\n #sb_widget .chat-section .content .content-bottom .new-chat-btn {\n display: inline-block;\n width: 70px;\n height: 26px;\n padding: 0 12px;\n text-align: center;\n line-height: 26px;\n font-size: 13px;\n letter-spacing: 0.85px; }\n #sb_widget .chat-section .content .content-bottom .new-chat-btn .sb-spinner div {\n width: 8px;\n height: 8px;\n margin-top: 4px;\n background-color: #35A300; }\n #sb_widget .chat-section .content .content-bottom .new-chat-btn .sb-spinner :nth-child(2) {\n margin: 0 4px; }\n #sb_widget .chat-section .content .content-bottom .new-chat-btn.disabled {\n cursor: default; }\n #sb_widget .chat-section .content .message-content {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: calc(100% - 16px);\n height: 328px;\n min-height: 240px;\n max-height: 328px;\n overflow-x: hidden;\n overflow-y: scroll;\n padding: 0 8px 8px 8px; }\n #sb_widget .chat-section .content .typing {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: none;\n width: calc(100% - 16px);\n height: 22px;\n padding: 0 8px;\n font-size: 12px;\n color: #C3CBD9;\n line-height: 22px; }\n #sb_widget .chat-section .content .typing .sb-spinner {\n top: initial;\n position: static;\n -webkit-transform: translate(0, 0);\n -moz-transform: translate(0, 0);\n -ms-transform: translate(0, 0);\n -o-transform: translate(0, 0);\n transform: translate(0, 0);\n display: inline-block;\n width: auto;\n text-align: left;\n margin-right: 8px; }\n #sb_widget .chat-section .content .typing .sb-spinner div {\n background-color: #A5B4CD;\n width: 6px;\n height: 6px; }\n #sb_widget .chat-section .content .typing .sb-spinner :nth-child(2) {\n margin: 0 3px; }\n #sb_widget .chat-section .content .input {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: calc(100% - 16px);\n min-height: 51px;\n max-height: 118px;\n padding: 0 8px;\n border-top: 1px solid #E5E5E5; }\n #sb_widget .chat-section .content .input .text {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: calc(100% - 8px);\n min-height: 24px;\n max-height: 90px;\n padding: 5px 8px 0 0;\n outline: none !important;\n overflow-x: hidden;\n overflow-y: auto;\n word-wrap: break-word;\n resize: none;\n border: 0;\n font-size: 13px;\n color: #485874;\n background-color: #FFFFFF; }\n #sb_widget .chat-section .content .input .text:focus {\n outline: 0; }\n #sb_widget .chat-section .content .input .text > div {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n height: 0px !important; }\n #sb_widget .chat-section .content .input .text:empty::before {\n font-size: 13px;\n content: \"Type a Message\";\n color: #C3CBD9; }\n #sb_widget .chat-section .content .input .text:focus:empty::before {\n content: \"\"; }\n #sb_widget .chat-section .content .input .file {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n float: left;\n width: 22px;\n height: 22px;\n cursor: pointer;\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-file-add-default.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat;\n background-position: inherit;\n background-size: 14px 14px; }\n #sb_widget .chat-section .content .input .file:hover {\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-file-add-over.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat;\n background-position: inherit;\n background-size: 14px 14px; }\n #sb_widget .chat-section .message-set {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: 100%;\n margin-top: 8px;\n float: left;\n direction: ltr;\n text-align: left; }\n #sb_widget .chat-section .message-set .image {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n float: inherit;\n width: 32px;\n height: 32px;\n margin-right: 8px;\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/thumnail-member-01.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat;\n background-position: inherit; }\n #sb_widget .chat-section .message-set .message {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n float: inherit; }\n #sb_widget .chat-section .message-set .nickname {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n font-size: 12px;\n color: #8090B4; }\n #sb_widget .chat-section .message-set .message-item {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n float: inherit; }\n #sb_widget .chat-section .message-set .message-item .text {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: inline-block;\n text-align: inherit;\n max-width: 180px;\n background-color: #F0F0F5;\n color: #444444;\n font-size: 13px;\n padding: 6px;\n word-wrap: break-word;\n border-radius: 5px;\n -webkit-border-radius: 5px;\n -moz-border-radius: 5px;\n -ms-border-radius: 5px;\n -o-border-radius: 5px; }\n #sb_widget .chat-section .message-set .message-item .file-message {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: inline-block; }\n #sb_widget .chat-section .message-set .message-item .file-message .image {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: inline-block;\n text-align: inherit;\n width: 160px;\n height: 160px;\n cursor: pointer;\n vertical-align: middle;\n background-position: center;\n background-size: 160px 160px;\n background-repeat: no-repeat;\n border-radius: 5px;\n -webkit-border-radius: 5px;\n -moz-border-radius: 5px;\n -ms-border-radius: 5px;\n -o-border-radius: 5px; }\n #sb_widget .chat-section .message-set .message-item .file {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: inline-flex;\n text-align: inherit;\n max-width: 180px;\n background-color: transparent;\n color: #444444;\n font-size: 13px;\n word-wrap: break-word;\n cursor: pointer;\n text-decoration: none;\n vertical-align: bottom; }\n #sb_widget .chat-section .message-set .message-item .file > .file-icon {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: inline-block;\n width: 24px;\n height: 26px;\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/icon-file.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .chat-section .message-set .message-item .file > .file-text {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n margin: 0 0 0 8px;\n max-width: calc(100% - 24px - 8px); }\n #sb_widget .chat-section .message-set .message-item .file > .file-text > .file-name {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: inline-block;\n max-width: 100%;\n -ms-text-overflow: ellipsis;\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden; }\n #sb_widget .chat-section .message-set .message-item .file > .file-text > .file-download {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n font-size: 11px;\n line-height: 6px;\n color: #0081D6; }\n #sb_widget .chat-section .message-set .message-item .unread {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: none !important;\n background-color: transparent;\n color: #A08CFF;\n font-size: 11px;\n font-weight: 700;\n text-align: center;\n margin: 0 4px;\n vertical-align: bottom; }\n #sb_widget .chat-section .message-set.user {\n float: right; }\n #sb_widget .chat-section .message-set.user .image,\n #sb_widget .chat-section .message-set.user .nickname {\n display: none; }\n #sb_widget .chat-section .message-set.user .message-item {\n float: inherit; }\n #sb_widget .chat-section .message-set.user .message-item .text {\n background: #896BF5;\n color: #FFFFFF; }\n #sb_widget .chat-section .message-set.user .message-item .image {\n display: inline-block;\n text-align: inherit;\n width: 160px;\n height: 160px;\n cursor: pointer;\n margin: 0;\n background-position: center;\n background-size: 160px 160px;\n background-repeat: no-repeat;\n border-radius: 5px;\n -webkit-border-radius: 5px;\n -moz-border-radius: 5px;\n -ms-border-radius: 5px;\n -o-border-radius: 5px; }\n #sb_widget .chat-section .message-set.user .message-item .unread {\n display: inline-block !important; }\n #sb_widget .chat-section .message-set.time {\n text-align: center;\n font-size: 11px;\n color: #8090B4; }\n #sb_widget .chat-section .message-set.admin-message {\n text-align: center;\n font-size: 12px;\n color: #67769A; }\n #sb_widget .popup {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: none;\n background-color: transparent;\n position: absolute;\n bottom: 26px; }\n #sb_widget .popup .popup-body {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: 260px;\n height: 360px;\n background-color: #FFFFFF;\n -webkit-box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1), 0 5px 60px rgba(0, 0, 0, 0.35);\n -moz-box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1), 0 5px 60px rgba(0, 0, 0, 0.35);\n box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1), 0 5px 60px rgba(0, 0, 0, 0.35); }\n #sb_widget .popup .popup-body::before {\n content: ' ';\n position: absolute;\n bottom: 100%;\n left: 50%;\n margin-left: -5px;\n border-width: 7px;\n border-style: solid;\n border-color: transparent transparent #FFFFFF transparent; }\n #sb_widget .popup .popup-body > .content {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n overflow-y: scroll;\n overflow-x: hidden;\n height: calc(100% - 51px - 2px);\n margin: 0; }\n #sb_widget .popup .popup-body > .content > ul {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: 100%;\n min-height: 306px;\n margin: 0 0 2px 0;\n padding: 0;\n list-style-type: none; }\n #sb_widget .popup .popup-body > .content > ul > .sb-spinner, #sb_widget .popup .chat-section .popup-body > .content > ul > .sb-spinner {\n position: absolute; }\n #sb_widget .popup .popup-body > .content > ul > .sb-spinner div, #sb_widget .popup .chat-section .popup-body > .content > ul > .sb-spinner div {\n width: 12px;\n height: 12px; }\n #sb_widget .popup .popup-body > .content > ul > .sb-spinner :nth-child(2), #sb_widget .popup .chat-section .popup-body > .content > ul > .sb-spinner :nth-child(2) {\n margin: 0 6px; }\n #sb_widget .popup .popup-body > .content > ul > li {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: inline-table;\n width: calc(100% - 24px);\n height: calc(44px - 11px);\n background: #FFFFFF;\n padding: 0 12px;\n cursor: pointer; }\n #sb_widget .popup .popup-body > .content > ul > li:hover {\n background-color: #F5F8FA; }\n #sb_widget .popup .popup-body > .content > ul > li > div {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: inline-block;\n width: 100%;\n padding: 5px 0;\n border-bottom: 1px solid #E5E5E5; }\n #sb_widget .popup .popup-body > .content > ul > li .user-select {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: inline-block;\n margin-right: 8px;\n position: relative;\n top: 50%;\n width: 16px;\n height: 16px;\n -webkit-transform: translate(0, -50%);\n -moz-transform: translate(0, -50%);\n -ms-transform: translate(0, -50%);\n -o-transform: translate(0, -50%);\n transform: translate(0, -50%);\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-check-off.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .popup .popup-body > .content > ul > li .user-select.active {\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/btn-check-on.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .popup .popup-body > .content > ul > li .image-me {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n width: 31px;\n height: 31px;\n position: absolute;\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/icon-member-me.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .popup .popup-body > .content > ul > li .image {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: inline-block;\n margin-right: 8px;\n width: 31px;\n height: 31px;\n background-image: url(\"https://dxstmhyqfqr1o.cloudfront.net/widget/thumnail-member-01.svg\");\n background-position: center;\n background-size: cover;\n background-repeat: no-repeat; }\n #sb_widget .popup .popup-body > .content > ul > li .nickname {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n display: inline-block;\n font-size: 13px;\n color: #67769A;\n line-height: 31px;\n max-width: 70%;\n overflow: hidden;\n -ms-text-overflow: ellipsis;\n text-overflow: ellipsis;\n white-space: nowrap; }\n #sb_widget .popup .popup-top {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n height: 36px;\n background-color: #F3F5F7;\n padding: 0 12px;\n -webkit-box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.2);\n -moz-box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.2);\n box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.2); }\n #sb_widget .popup .popup-top .title {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n float: left;\n font-size: 13px;\n color: #67769A;\n line-height: 36px; }\n #sb_widget .popup .popup-top .count {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n float: left;\n width: 16px;\n height: 16px;\n margin-left: 8px;\n background-color: #D5D7D9;\n font-weight: 700;\n font-size: 10px;\n color: #67769A;\n text-align: center;\n line-height: 16px;\n position: relative;\n top: 50%;\n -webkit-transform: translate(0, -50%);\n -moz-transform: translate(0, -50%);\n -ms-transform: translate(0, -50%);\n -o-transform: translate(0, -50%);\n transform: translate(0, -50%); }\n #sb_widget .popup .popup-top .btn {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n float: right;\n width: 24px;\n height: 26px;\n position: relative;\n top: 50%;\n cursor: pointer;\n -webkit-transform: translate(0, -50%);\n -moz-transform: translate(0, -50%);\n -ms-transform: translate(0, -50%);\n -o-transform: translate(0, -50%);\n transform: translate(0, -50%); }\n #sb_widget .popup .popup-bottom {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n height: 52px;\n background-color: #FFFFFF;\n border-top: 1px solid rgba(0, 0, 0, 0.2);\n padding: 0 12px; }\n #sb_widget .popup .popup-bottom .title {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n float: left;\n font-size: 13px;\n line-height: 52px;\n color: #67769A; }\n #sb_widget .popup .popup-bottom .count {\n margin: 0;\n padding: 0;\n font-size: 100%;\n line-height: 1;\n width: auto;\n height: auto;\n box-sizing: initial;\n float: left;\n width: 16px;\n height: 16px;\n margin-left: 8px;\n background-color: #F0F0F2;\n font-weight: 700;\n font-size: 10px;\n color: #67769A;\n text-align: center;\n line-height: 16px;\n position: relative;\n top: 50%;\n -webkit-transform: translate(0, -50%);\n -moz-transform: translate(0, -50%);\n -ms-transform: translate(0, -50%);\n -o-transform: translate(0, -50%);\n transform: translate(0, -50%); }\n #sb_widget .popup .popup-bottom .invite-btn {\n float: right;\n position: relative;\n top: 50%;\n width: 41px;\n height: 24px;\n font-size: 14px;\n line-height: 24px;\n letter-spacing: 0.85px;\n -webkit-transform: translate(0, -50%);\n -moz-transform: translate(0, -50%);\n -ms-transform: translate(0, -50%);\n -o-transform: translate(0, -50%);\n transform: translate(0, -50%); }\n #sb_widget .popup .popup-bottom .invite-btn .sb-spinner {\n margin-top: 4px; }\n #sb_widget .popup .popup-bottom .invite-btn .sb-spinner div {\n width: 8px;\n height: 8px;\n margin-top: 4px;\n background-color: #35A300; }\n #sb_widget .popup .popup-bottom .invite-btn .sb-spinner :nth-child(2) {\n margin: 0 4px; }\n #sb_widget .popup .popup-bottom .invite-btn.disabled {\n cursor: default; }\n #sb_widget .popup.members .popup-body::before {\n border-color: transparent transparent #F3F5F7 transparent; }\n #sb_widget .popup.members .popup-body > .content {\n height: calc(100% - 36px - 2px); }\n #sb_widget .popup.members .popup-body > .content > ul {\n height: 322px;\n margin: 2px 0 0 0; }\n #sb_widget .popup.members .popup-body > .content > ul > li {\n cursor: default; }\n", ""]); - -// exports - - -/***/ }), -/* 309 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(Buffer) {/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ -// css base code, injected by the css-loader -module.exports = function(useSourceMap) { - var list = []; - - // return the list of modules as css string - list.toString = function toString() { - return this.map(function (item) { - var content = cssWithMappingToString(item, useSourceMap); - if(item[2]) { - return "@media " + item[2] + "{" + content + "}"; - } else { - return content; - } - }).join(""); - }; - - // import a list of modules into the list - list.i = function(modules, mediaQuery) { - if(typeof modules === "string") - modules = [[null, modules, ""]]; - var alreadyImportedModules = {}; - for(var i = 0; i < this.length; i++) { - var id = this[i][0]; - if(typeof id === "number") - alreadyImportedModules[id] = true; - } - for(i = 0; i < modules.length; i++) { - var item = modules[i]; - // skip already imported module - // this implementation is not 100% perfect for weird media query combinations - // when a module is imported multiple times with different media queries. - // I hope this will never occur (Hey this way we have smaller bundles) - if(typeof item[0] !== "number" || !alreadyImportedModules[item[0]]) { - if(mediaQuery && !item[2]) { - item[2] = mediaQuery; - } else if(mediaQuery) { - item[2] = "(" + item[2] + ") and (" + mediaQuery + ")"; - } - list.push(item); - } - } - }; - return list; -}; - -function cssWithMappingToString(item, useSourceMap) { - var content = item[1] || ''; - var cssMapping = item[3]; - if (!cssMapping) { - return content; - } - - if (useSourceMap) { - var sourceMapping = toComment(cssMapping); - var sourceURLs = cssMapping.sources.map(function (source) { - return '/*# sourceURL=' + cssMapping.sourceRoot + source + ' */' - }); - - return [content].concat(sourceURLs).concat([sourceMapping]).join('\n'); - } - - return [content].join('\n'); -} - -// Adapted from convert-source-map (MIT) -function toComment(sourceMap) { - var base64 = new Buffer(JSON.stringify(sourceMap)).toString('base64'); - var data = 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + base64; - - return '/*# ' + data + ' */'; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(126).Buffer)) - -/***/ }), -/* 310 */ -/***/ (function(module, exports) { - -exports.read = function (buffer, offset, isLE, mLen, nBytes) { - var e, m - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var nBits = -7 - var i = isLE ? (nBytes - 1) : 0 - var d = isLE ? -1 : 1 - var s = buffer[offset + i] - - i += d - - e = s & ((1 << (-nBits)) - 1) - s >>= (-nBits) - nBits += eLen - for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} - - m = e & ((1 << (-nBits)) - 1) - e >>= (-nBits) - nBits += mLen - for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} - - if (e === 0) { - e = 1 - eBias - } else if (e === eMax) { - return m ? NaN : ((s ? -1 : 1) * Infinity) - } else { - m = m + Math.pow(2, mLen) - e = e - eBias - } - return (s ? -1 : 1) * m * Math.pow(2, e - mLen) -} - -exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { - var e, m, c - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) - var i = isLE ? 0 : (nBytes - 1) - var d = isLE ? 1 : -1 - var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 - - value = Math.abs(value) - - if (isNaN(value) || value === Infinity) { - m = isNaN(value) ? 1 : 0 - e = eMax - } else { - e = Math.floor(Math.log(value) / Math.LN2) - if (value * (c = Math.pow(2, -e)) < 1) { - e-- - c *= 2 - } - if (e + eBias >= 1) { - value += rt / c - } else { - value += rt * Math.pow(2, 1 - eBias) - } - if (value * c >= 2) { - e++ - c /= 2 - } - - if (e + eBias >= eMax) { - m = 0 - e = eMax - } else if (e + eBias >= 1) { - m = (value * c - 1) * Math.pow(2, mLen) - e = e + eBias - } else { - m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) - e = 0 - } - } - - for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} - - e = (e << mLen) | m - eLen += mLen - for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} - - buffer[offset + i - d] |= s * 128 -} - - -/***/ }), -/* 311 */ -/***/ (function(module, exports) { - -var toString = {}.toString; - -module.exports = Array.isArray || function (arr) { - return toString.call(arr) == '[object Array]'; -}; - - -/***/ }), -/* 312 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(global) {/** - * Copyright (c) 2014, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * https://raw.github.com/facebook/regenerator/master/LICENSE file. An - * additional grant of patent rights can be found in the PATENTS file in - * the same directory. - */ - -!(function(global) { - "use strict"; - - var Op = Object.prototype; - var hasOwn = Op.hasOwnProperty; - var undefined; // More compressible than void 0. - var $Symbol = typeof Symbol === "function" ? Symbol : {}; - var iteratorSymbol = $Symbol.iterator || "@@iterator"; - var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator"; - var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag"; - - var inModule = typeof module === "object"; - var runtime = global.regeneratorRuntime; - if (runtime) { - if (inModule) { - // If regeneratorRuntime is defined globally and we're in a module, - // make the exports object identical to regeneratorRuntime. - module.exports = runtime; - } - // Don't bother evaluating the rest of this file if the runtime was - // already defined globally. - return; - } - - // Define the runtime globally (as expected by generated code) as either - // module.exports (if we're in a module) or a new, empty object. - runtime = global.regeneratorRuntime = inModule ? module.exports : {}; - - function wrap(innerFn, outerFn, self, tryLocsList) { - // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator. - var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator; - var generator = Object.create(protoGenerator.prototype); - var context = new Context(tryLocsList || []); - - // The ._invoke method unifies the implementations of the .next, - // .throw, and .return methods. - generator._invoke = makeInvokeMethod(innerFn, self, context); - - return generator; - } - runtime.wrap = wrap; - - // Try/catch helper to minimize deoptimizations. Returns a completion - // record like context.tryEntries[i].completion. This interface could - // have been (and was previously) designed to take a closure to be - // invoked without arguments, but in all the cases we care about we - // already have an existing method we want to call, so there's no need - // to create a new function object. We can even get away with assuming - // the method takes exactly one argument, since that happens to be true - // in every case, so we don't have to touch the arguments object. The - // only additional allocation required is the completion record, which - // has a stable shape and so hopefully should be cheap to allocate. - function tryCatch(fn, obj, arg) { - try { - return { type: "normal", arg: fn.call(obj, arg) }; - } catch (err) { - return { type: "throw", arg: err }; - } - } - - var GenStateSuspendedStart = "suspendedStart"; - var GenStateSuspendedYield = "suspendedYield"; - var GenStateExecuting = "executing"; - var GenStateCompleted = "completed"; - - // Returning this object from the innerFn has the same effect as - // breaking out of the dispatch switch statement. - var ContinueSentinel = {}; - - // Dummy constructor functions that we use as the .constructor and - // .constructor.prototype properties for functions that return Generator - // objects. For full spec compliance, you may wish to configure your - // minifier not to mangle the names of these two functions. - function Generator() {} - function GeneratorFunction() {} - function GeneratorFunctionPrototype() {} - - // This is a polyfill for %IteratorPrototype% for environments that - // don't natively support it. - var IteratorPrototype = {}; - IteratorPrototype[iteratorSymbol] = function () { - return this; - }; - - var getProto = Object.getPrototypeOf; - var NativeIteratorPrototype = getProto && getProto(getProto(values([]))); - if (NativeIteratorPrototype && - NativeIteratorPrototype !== Op && - hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) { - // This environment has a native %IteratorPrototype%; use it instead - // of the polyfill. - IteratorPrototype = NativeIteratorPrototype; - } - - var Gp = GeneratorFunctionPrototype.prototype = - Generator.prototype = Object.create(IteratorPrototype); - GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype; - GeneratorFunctionPrototype.constructor = GeneratorFunction; - GeneratorFunctionPrototype[toStringTagSymbol] = - GeneratorFunction.displayName = "GeneratorFunction"; - - // Helper for defining the .next, .throw, and .return methods of the - // Iterator interface in terms of a single ._invoke method. - function defineIteratorMethods(prototype) { - ["next", "throw", "return"].forEach(function(method) { - prototype[method] = function(arg) { - return this._invoke(method, arg); - }; - }); - } - - runtime.isGeneratorFunction = function(genFun) { - var ctor = typeof genFun === "function" && genFun.constructor; - return ctor - ? ctor === GeneratorFunction || - // For the native GeneratorFunction constructor, the best we can - // do is to check its .name property. - (ctor.displayName || ctor.name) === "GeneratorFunction" - : false; - }; - - runtime.mark = function(genFun) { - if (Object.setPrototypeOf) { - Object.setPrototypeOf(genFun, GeneratorFunctionPrototype); - } else { - genFun.__proto__ = GeneratorFunctionPrototype; - if (!(toStringTagSymbol in genFun)) { - genFun[toStringTagSymbol] = "GeneratorFunction"; - } - } - genFun.prototype = Object.create(Gp); - return genFun; - }; - - // Within the body of any async function, `await x` is transformed to - // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test - // `hasOwn.call(value, "__await")` to determine if the yielded value is - // meant to be awaited. - runtime.awrap = function(arg) { - return { __await: arg }; - }; - - function AsyncIterator(generator) { - function invoke(method, arg, resolve, reject) { - var record = tryCatch(generator[method], generator, arg); - if (record.type === "throw") { - reject(record.arg); - } else { - var result = record.arg; - var value = result.value; - if (value && - typeof value === "object" && - hasOwn.call(value, "__await")) { - return Promise.resolve(value.__await).then(function(value) { - invoke("next", value, resolve, reject); - }, function(err) { - invoke("throw", err, resolve, reject); - }); - } - - return Promise.resolve(value).then(function(unwrapped) { - // When a yielded Promise is resolved, its final value becomes - // the .value of the Promise<{value,done}> result for the - // current iteration. If the Promise is rejected, however, the - // result for this iteration will be rejected with the same - // reason. Note that rejections of yielded Promises are not - // thrown back into the generator function, as is the case - // when an awaited Promise is rejected. This difference in - // behavior between yield and await is important, because it - // allows the consumer to decide what to do with the yielded - // rejection (swallow it and continue, manually .throw it back - // into the generator, abandon iteration, whatever). With - // await, by contrast, there is no opportunity to examine the - // rejection reason outside the generator function, so the - // only option is to throw it from the await expression, and - // let the generator function handle the exception. - result.value = unwrapped; - resolve(result); - }, reject); - } - } - - if (typeof global.process === "object" && global.process.domain) { - invoke = global.process.domain.bind(invoke); - } - - var previousPromise; - - function enqueue(method, arg) { - function callInvokeWithMethodAndArg() { - return new Promise(function(resolve, reject) { - invoke(method, arg, resolve, reject); - }); - } - - return previousPromise = - // If enqueue has been called before, then we want to wait until - // all previous Promises have been resolved before calling invoke, - // so that results are always delivered in the correct order. If - // enqueue has not been called before, then it is important to - // call invoke immediately, without waiting on a callback to fire, - // so that the async generator function has the opportunity to do - // any necessary setup in a predictable way. This predictability - // is why the Promise constructor synchronously invokes its - // executor callback, and why async functions synchronously - // execute code before the first await. Since we implement simple - // async functions in terms of async generators, it is especially - // important to get this right, even though it requires care. - previousPromise ? previousPromise.then( - callInvokeWithMethodAndArg, - // Avoid propagating failures to Promises returned by later - // invocations of the iterator. - callInvokeWithMethodAndArg - ) : callInvokeWithMethodAndArg(); - } - - // Define the unified helper method that is used to implement .next, - // .throw, and .return (see defineIteratorMethods). - this._invoke = enqueue; - } - - defineIteratorMethods(AsyncIterator.prototype); - AsyncIterator.prototype[asyncIteratorSymbol] = function () { - return this; - }; - runtime.AsyncIterator = AsyncIterator; - - // Note that simple async functions are implemented on top of - // AsyncIterator objects; they just return a Promise for the value of - // the final result produced by the iterator. - runtime.async = function(innerFn, outerFn, self, tryLocsList) { - var iter = new AsyncIterator( - wrap(innerFn, outerFn, self, tryLocsList) - ); - - return runtime.isGeneratorFunction(outerFn) - ? iter // If outerFn is a generator, return the full iterator. - : iter.next().then(function(result) { - return result.done ? result.value : iter.next(); - }); - }; - - function makeInvokeMethod(innerFn, self, context) { - var state = GenStateSuspendedStart; - - return function invoke(method, arg) { - if (state === GenStateExecuting) { - throw new Error("Generator is already running"); - } - - if (state === GenStateCompleted) { - if (method === "throw") { - throw arg; - } - - // Be forgiving, per 25.3.3.3.3 of the spec: - // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume - return doneResult(); - } - - context.method = method; - context.arg = arg; - - while (true) { - var delegate = context.delegate; - if (delegate) { - var delegateResult = maybeInvokeDelegate(delegate, context); - if (delegateResult) { - if (delegateResult === ContinueSentinel) continue; - return delegateResult; - } - } - - if (context.method === "next") { - // Setting context._sent for legacy support of Babel's - // function.sent implementation. - context.sent = context._sent = context.arg; - - } else if (context.method === "throw") { - if (state === GenStateSuspendedStart) { - state = GenStateCompleted; - throw context.arg; - } - - context.dispatchException(context.arg); - - } else if (context.method === "return") { - context.abrupt("return", context.arg); - } - - state = GenStateExecuting; - - var record = tryCatch(innerFn, self, context); - if (record.type === "normal") { - // If an exception is thrown from innerFn, we leave state === - // GenStateExecuting and loop back for another invocation. - state = context.done - ? GenStateCompleted - : GenStateSuspendedYield; - - if (record.arg === ContinueSentinel) { - continue; - } - - return { - value: record.arg, - done: context.done - }; - - } else if (record.type === "throw") { - state = GenStateCompleted; - // Dispatch the exception by looping back around to the - // context.dispatchException(context.arg) call above. - context.method = "throw"; - context.arg = record.arg; - } - } - }; - } - - // Call delegate.iterator[context.method](context.arg) and handle the - // result, either by returning a { value, done } result from the - // delegate iterator, or by modifying context.method and context.arg, - // setting context.delegate to null, and returning the ContinueSentinel. - function maybeInvokeDelegate(delegate, context) { - var method = delegate.iterator[context.method]; - if (method === undefined) { - // A .throw or .return when the delegate iterator has no .throw - // method always terminates the yield* loop. - context.delegate = null; - - if (context.method === "throw") { - if (delegate.iterator.return) { - // If the delegate iterator has a return method, give it a - // chance to clean up. - context.method = "return"; - context.arg = undefined; - maybeInvokeDelegate(delegate, context); - - if (context.method === "throw") { - // If maybeInvokeDelegate(context) changed context.method from - // "return" to "throw", let that override the TypeError below. - return ContinueSentinel; - } - } - - context.method = "throw"; - context.arg = new TypeError( - "The iterator does not provide a 'throw' method"); - } - - return ContinueSentinel; - } - - var record = tryCatch(method, delegate.iterator, context.arg); - - if (record.type === "throw") { - context.method = "throw"; - context.arg = record.arg; - context.delegate = null; - return ContinueSentinel; - } - - var info = record.arg; - - if (! info) { - context.method = "throw"; - context.arg = new TypeError("iterator result is not an object"); - context.delegate = null; - return ContinueSentinel; - } - - if (info.done) { - // Assign the result of the finished delegate to the temporary - // variable specified by delegate.resultName (see delegateYield). - context[delegate.resultName] = info.value; - - // Resume execution at the desired location (see delegateYield). - context.next = delegate.nextLoc; - - // If context.method was "throw" but the delegate handled the - // exception, let the outer generator proceed normally. If - // context.method was "next", forget context.arg since it has been - // "consumed" by the delegate iterator. If context.method was - // "return", allow the original .return call to continue in the - // outer generator. - if (context.method !== "return") { - context.method = "next"; - context.arg = undefined; - } - - } else { - // Re-yield the result returned by the delegate method. - return info; - } - - // The delegate iterator is finished, so forget it and continue with - // the outer generator. - context.delegate = null; - return ContinueSentinel; - } - - // Define Generator.prototype.{next,throw,return} in terms of the - // unified ._invoke helper method. - defineIteratorMethods(Gp); - - Gp[toStringTagSymbol] = "Generator"; - - // A Generator should always return itself as the iterator object when the - // @@iterator function is called on it. Some browsers' implementations of the - // iterator prototype chain incorrectly implement this, causing the Generator - // object to not be returned from this call. This ensures that doesn't happen. - // See https://github.com/facebook/regenerator/issues/274 for more details. - Gp[iteratorSymbol] = function() { - return this; - }; - - Gp.toString = function() { - return "[object Generator]"; - }; - - function pushTryEntry(locs) { - var entry = { tryLoc: locs[0] }; - - if (1 in locs) { - entry.catchLoc = locs[1]; - } - - if (2 in locs) { - entry.finallyLoc = locs[2]; - entry.afterLoc = locs[3]; - } - - this.tryEntries.push(entry); - } - - function resetTryEntry(entry) { - var record = entry.completion || {}; - record.type = "normal"; - delete record.arg; - entry.completion = record; - } - - function Context(tryLocsList) { - // The root entry object (effectively a try statement without a catch - // or a finally block) gives us a place to store values thrown from - // locations where there is no enclosing try statement. - this.tryEntries = [{ tryLoc: "root" }]; - tryLocsList.forEach(pushTryEntry, this); - this.reset(true); - } - - runtime.keys = function(object) { - var keys = []; - for (var key in object) { - keys.push(key); - } - keys.reverse(); - - // Rather than returning an object with a next method, we keep - // things simple and return the next function itself. - return function next() { - while (keys.length) { - var key = keys.pop(); - if (key in object) { - next.value = key; - next.done = false; - return next; - } - } - - // To avoid creating an additional object, we just hang the .value - // and .done properties off the next function object itself. This - // also ensures that the minifier will not anonymize the function. - next.done = true; - return next; - }; - }; - - function values(iterable) { - if (iterable) { - var iteratorMethod = iterable[iteratorSymbol]; - if (iteratorMethod) { - return iteratorMethod.call(iterable); - } - - if (typeof iterable.next === "function") { - return iterable; - } - - if (!isNaN(iterable.length)) { - var i = -1, next = function next() { - while (++i < iterable.length) { - if (hasOwn.call(iterable, i)) { - next.value = iterable[i]; - next.done = false; - return next; - } - } - - next.value = undefined; - next.done = true; - - return next; - }; - - return next.next = next; - } - } - - // Return an iterator with no values. - return { next: doneResult }; - } - runtime.values = values; - - function doneResult() { - return { value: undefined, done: true }; - } - - Context.prototype = { - constructor: Context, - - reset: function(skipTempReset) { - this.prev = 0; - this.next = 0; - // Resetting context._sent for legacy support of Babel's - // function.sent implementation. - this.sent = this._sent = undefined; - this.done = false; - this.delegate = null; - - this.method = "next"; - this.arg = undefined; - - this.tryEntries.forEach(resetTryEntry); - - if (!skipTempReset) { - for (var name in this) { - // Not sure about the optimal order of these conditions: - if (name.charAt(0) === "t" && - hasOwn.call(this, name) && - !isNaN(+name.slice(1))) { - this[name] = undefined; - } - } - } - }, - - stop: function() { - this.done = true; - - var rootEntry = this.tryEntries[0]; - var rootRecord = rootEntry.completion; - if (rootRecord.type === "throw") { - throw rootRecord.arg; - } - - return this.rval; - }, - - dispatchException: function(exception) { - if (this.done) { - throw exception; - } - - var context = this; - function handle(loc, caught) { - record.type = "throw"; - record.arg = exception; - context.next = loc; - - if (caught) { - // If the dispatched exception was caught by a catch block, - // then let that catch block handle the exception normally. - context.method = "next"; - context.arg = undefined; - } - - return !! caught; - } - - for (var i = this.tryEntries.length - 1; i >= 0; --i) { - var entry = this.tryEntries[i]; - var record = entry.completion; - - if (entry.tryLoc === "root") { - // Exception thrown outside of any try block that could handle - // it, so set the completion value of the entire function to - // throw the exception. - return handle("end"); - } - - if (entry.tryLoc <= this.prev) { - var hasCatch = hasOwn.call(entry, "catchLoc"); - var hasFinally = hasOwn.call(entry, "finallyLoc"); - - if (hasCatch && hasFinally) { - if (this.prev < entry.catchLoc) { - return handle(entry.catchLoc, true); - } else if (this.prev < entry.finallyLoc) { - return handle(entry.finallyLoc); - } - - } else if (hasCatch) { - if (this.prev < entry.catchLoc) { - return handle(entry.catchLoc, true); - } - - } else if (hasFinally) { - if (this.prev < entry.finallyLoc) { - return handle(entry.finallyLoc); - } - - } else { - throw new Error("try statement without catch or finally"); - } - } - } - }, - - abrupt: function(type, arg) { - for (var i = this.tryEntries.length - 1; i >= 0; --i) { - var entry = this.tryEntries[i]; - if (entry.tryLoc <= this.prev && - hasOwn.call(entry, "finallyLoc") && - this.prev < entry.finallyLoc) { - var finallyEntry = entry; - break; - } - } - - if (finallyEntry && - (type === "break" || - type === "continue") && - finallyEntry.tryLoc <= arg && - arg <= finallyEntry.finallyLoc) { - // Ignore the finally entry if control is not jumping to a - // location outside the try/catch block. - finallyEntry = null; - } - - var record = finallyEntry ? finallyEntry.completion : {}; - record.type = type; - record.arg = arg; - - if (finallyEntry) { - this.method = "next"; - this.next = finallyEntry.finallyLoc; - return ContinueSentinel; - } - - return this.complete(record); - }, - - complete: function(record, afterLoc) { - if (record.type === "throw") { - throw record.arg; - } - - if (record.type === "break" || - record.type === "continue") { - this.next = record.arg; - } else if (record.type === "return") { - this.rval = this.arg = record.arg; - this.method = "return"; - this.next = "end"; - } else if (record.type === "normal" && afterLoc) { - this.next = afterLoc; - } - - return ContinueSentinel; - }, - - finish: function(finallyLoc) { - for (var i = this.tryEntries.length - 1; i >= 0; --i) { - var entry = this.tryEntries[i]; - if (entry.finallyLoc === finallyLoc) { - this.complete(entry.completion, entry.afterLoc); - resetTryEntry(entry); - return ContinueSentinel; - } - } - }, - - "catch": function(tryLoc) { - for (var i = this.tryEntries.length - 1; i >= 0; --i) { - var entry = this.tryEntries[i]; - if (entry.tryLoc === tryLoc) { - var record = entry.completion; - if (record.type === "throw") { - var thrown = record.arg; - resetTryEntry(entry); - } - return thrown; - } - } - - // The context.catch method must only be called with a location - // argument that corresponds to a known catch block. - throw new Error("illegal catch attempt"); - }, - - delegateYield: function(iterable, resultName, nextLoc) { - this.delegate = { - iterator: values(iterable), - resultName: resultName, - nextLoc: nextLoc - }; - - if (this.method === "next") { - // Deliberately forget the last sent value so that we don't - // accidentally pass it on to the delegate. - this.arg = undefined; - } - - return ContinueSentinel; - } - }; -})( - // Among the various tricks for obtaining a reference to the global - // object, this seems to be the most reliable technique that does not - // use indirect eval (which violates Content Security Policy). - typeof global === "object" ? global : - typeof window === "object" ? window : - typeof self === "object" ? self : this -); - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(88))) - -/***/ }), -/* 313 */ -/***/ (function(module, exports, __webpack_require__) { - -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ -var stylesInDom = {}, - memoize = function(fn) { - var memo; - return function () { - if (typeof memo === "undefined") memo = fn.apply(this, arguments); - return memo; - }; - }, - isOldIE = memoize(function() { - return /msie [6-9]\b/.test(self.navigator.userAgent.toLowerCase()); - }), - getHeadElement = memoize(function () { - return document.head || document.getElementsByTagName("head")[0]; - }), - singletonElement = null, - singletonCounter = 0, - styleElementsInsertedAtTop = [], - fixUrls = __webpack_require__(314); - -module.exports = function(list, options) { - if(typeof DEBUG !== "undefined" && DEBUG) { - if(typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment"); - } - - options = options || {}; - options.attrs = typeof options.attrs === "object" ? options.attrs : {}; - - // Force single-tag solution on IE6-9, which has a hard limit on the # of - - - - -
Ver.0.15.0
-
- -
- - - - - - - - diff --git a/web-widget/package.json b/web-widget/package.json deleted file mode 100644 index 088151a6..00000000 --- a/web-widget/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "widget-sample", - "version": "1.0.0", - "description": "SendBird Widget Sample", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "SendBird", - "license": "ISC", - "devDependencies": { - "babel-core": "^6.24.0", - "babel-eslint": "^7.1.1", - "babel-loader": "^6.4.1", - "babel-polyfill": "^6.23.0", - "babel-preset-env": "^1.2.2", - "babel-preset-es2015": "^6.24.0", - "css-loader": "^0.27.3", - "eslint": "^3.18.0", - "eslint-loader": "^1.6.3", - "node-sass": "^4.5.0", - "sass-loader": "^6.0.3", - "style-loader": "^0.14.1", - "webpack": "^2.2.1" - } -} diff --git a/web-widget/src/js/consts.js b/web-widget/src/js/consts.js deleted file mode 100644 index e75dd494..00000000 --- a/web-widget/src/js/consts.js +++ /dev/null @@ -1,96 +0,0 @@ -export const className = { - WIDGET_BTN: 'widget', - NOTIFICATION: 'notification', - - ACTIVE: 'active', - DISABLED: 'disabled', - - CHANNEL_BOARD: 'channel-board', - BOARD_TOP: 'board-top', - OPTION_MENU: 'option-menu', - OPTION_CONTENT: 'option-content', - - TITLE: 'title', - INPUT: 'input', - BTN: 'btn', - ITEM: 'item', - IMAGE: 'image', - TOP: 'top', - COUNT: 'count', - TIME: 'time', - UNREAD: 'unread', - - CONTENT: 'content', - LOGIN_FORM: 'login-form', - LOGIN_BTN: 'login-btn', - USER_ID: 'user-id', - NICKNAME: 'nickname', - - CHANNEL_LIST: 'channel-list', - CONTENT_TOP: 'content-top', - CONTENT_BOTTOM: 'content-bottom', - LAST_MESSAGE: 'last-message', - EMPTY_ITEM: 'empty-item', - - CHAT_SECTION: 'chat-section', - CHAT_BOARD: 'chat-board', - MESSAGE_CONTENT: 'message-content', - MESSAGE_LIST: 'message-list', - TYPING: 'typing', - TEXT: 'text', - FILE_MESSAGE: 'file-message', - FILE: 'file', - FILE_ICON: 'file-icon', - FILE_NAME: 'file-name', - FILE_DOWNLOAD: 'file-download', - FILE_TEXT: 'file-text', - MESSAGE_SET: 'message-set', - USER: 'user', - MESSAGE_ITEM: 'message-item', - MESSAGE: 'message', - USER_CONTENT: 'user-content', - NEW_CHAT_BTN: 'new-chat-btn', - USER_SELECT: 'user-select', - USER_ITEM: 'user-item', - LEAVE_POPUP: 'leave-popup', - LEAVE_BTN: 'leave-btn', - CANCEL_BTN: 'cancel-btn', - ADMIN_MESSAGE: 'admin-message', - - POPUP: 'popup', - MEMBERS: 'members', - INVITE: 'invite', - POPUP_BODY: 'popup-body', - POPUP_TOP: 'popup-top', - POPUP_CONTENT: 'popup-content', - POPUP_BOTTOM: 'popup-bottom', - INVITE_BTN: 'invite-btn', - IMAGE_ME: 'image-me', - - TOOLTIP: 'tooltip', - - IC_LOGIN: 'ic-login', - IC_CONNECTED: 'ic-connected', - IC_MINIMIZE: 'ic-minimize', - IC_OPTION: 'ic-option', - IC_NEW_CHAT: 'ic-new-chat', - IC_CLOSE: 'ic-close', - IC_MEMBERS: 'ic-members', - IC_INVITE: 'ic-invite', - IC_LEAVE: 'ic-leave', - - FADE_IN: 'sb-fade-in', - FADE_OUT: 'sb-fade-out', - SPINNER: 'sb-spinner' - -}; - -export const styleValue = { - CURSOR_INIT: '', - CURSOR_DEFAULT: 'default' -}; - -export const MAX_COUNT = '+9'; -export const MAX_FONT_ZISE = '11'; - -export const TYPE_STRING = 'string'; diff --git a/web-widget/src/js/elements/elements.js b/web-widget/src/js/elements/elements.js deleted file mode 100644 index 8b675515..00000000 --- a/web-widget/src/js/elements/elements.js +++ /dev/null @@ -1,172 +0,0 @@ -import '../../scss/widget.scss'; -import { removeClass, addClass } from '../utils.js'; -import { className, styleValue } from '../consts.js'; - -class Element { - constructor() { - this.tagName = { - DIV: 'div', - SPAN: 'span', - INPUT: 'input', - UL: 'ul', - LI: 'li', - TIME: 'time', - LABEL: 'label', - A: 'a', - IMG: 'img' - }; - this.eventName = { - CLICK: 'click', - KEYDOWN: 'keydown', - KEYUP: 'keyup', - CHANGE: 'change', - SCROLL: 'scroll', - PASTE: 'paste' - }; - } - - /* - Create Elements - */ - createDiv() { - return document.createElement(this.tagName.DIV); - } - - createTime() { - return document.createElement(this.tagName.TIME); - } - - createA() { - return document.createElement(this.tagName.A); - } - - createImg() { - return document.createElement(this.tagName.IMG); - } - - createSpan() { - return document.createElement(this.tagName.SPAN); - } - - createLabel() { - return document.createElement(this.tagName.LABEL); - } - - createInput() { - return document.createElement(this.tagName.INPUT); - } - - createUl() { - return document.createElement(this.tagName.UL); - } - - createLi() { - return document.createElement(this.tagName.LI); - } - - _setClass(...args) { - args.reduce((target, classes) => { - return target.className += classes.join(' '); - }); - } - - _setContent(target, text) { - target.innerHTML = text; - } - - _addContent(target, text) { - target.innerHTML += text; - } - - _setBackgroundImage(target, url) { - target.style.backgroundImage = 'url(' + url + ')'; - } - _setBackgroundSize(target, size) { - target.style.backgroundSize = size; - } - - _setFontSize(target, size) { - target.style.fontSize = size ? size + 'px' : null; - } - - _setHeight(target, height) { - target.style.height = height + 'px'; - } - - _setWidth(target, width) { - target.style.width = width + 'px'; - } - - _setRight(target, right) { - target.style.right = right + 'px'; - } - - _setDataset(target, name, data) { - target.setAttribute('data-' + name, data); - } - - _setClickEvent(...args) { - args.reduce((target, action) => { - target.addEventListener(this.eventName.CLICK, () => { - action(); - }); - }); - } - - _setPasteEvent(...args) { - args.reduce((target, action) => { - target.addEventListener(this.eventName.PASTE, (event) => { - action(event); - }); - }); - } - - _setKeyupEvent(...args) { - args.reduce((target, action) => { - target.addEventListener(this.eventName.KEYUP, (event) => { - action(event); - }); - }); - } - - _setKeydownEvent(...args) { - args.reduce((target, action) => { - target.addEventListener(this.eventName.KEYDOWN, (event) => { - action(event); - }); - }); - } - - _setChangeEvent(...args) { - args.reduce((target, action) => { - target.addEventListener(this.eventName.CHANGE, () => { - action(); - }); - }); - } - - _setScrollEvent(...args) { - args.reduce((target, action) => { - target.addEventListener(this.eventName.SCROLL, () => { - action(); - }); - }); - } - - _isBottom(target, list) { - return (target.scrollTop + target.offsetHeight) >= list.offsetHeight; - } - - enabledToggle(target, isEnabled) { - if (isEnabled || isEnabled === undefined) { - removeClass(target, className.DISABLED); - target.style.cursor = styleValue.CURSOR_INIT; - } else { - addClass(target, className.DISABLED); - target.style.cursor = styleValue.CURSOR_DEFAULT; - } - } - -} - -export { Element as default }; diff --git a/web-widget/src/js/sendbird.js b/web-widget/src/js/sendbird.js deleted file mode 100644 index 0907379c..00000000 --- a/web-widget/src/js/sendbird.js +++ /dev/null @@ -1,286 +0,0 @@ -import { MAX_COUNT } from './consts.js'; - -const GLOBAL_HANDLER = 'GLOBAL_HANDLER'; -const GET_MESSAGE_LIMIT = 20; - -class Sendbird { - constructor(appId) { - this.sb = new window.SendBird({ appId: appId }); - this.channelListQuery = null; - this.userListQuery = null; - } - - reset() { - this.channelListQuery = null; - this.userListQuery = null; - this.sb.removeChannelHandler(GLOBAL_HANDLER); - } - - isConnected() { - return !!this.sb.currentUser; - } - - connect(userId, nickname, action) { - this.sb.connect(userId.trim(), (user, error) => { - if (error) { - console.error(error); - return; - } - this.sb.updateCurrentUserInfo(nickname.trim(), '', (response, error) => { - if (error) { - console.error(error); - return; - } - action(); - }); - }); - } - - disconnect(action) { - if(this.isConnected()) { - this.sb.disconnect(() => { - action(); - }); - } - } - - isCurrentUser(user) { - return this.sb.currentUser.userId == user.userId; - } - - /* - Channel - */ - getChannelList(action) { - if (!this.channelListQuery) { - this.channelListQuery = this.sb.GroupChannel.createMyGroupChannelListQuery(); - this.channelListQuery.includeEmpty = true; - this.channelListQuery.limit = 20; - } - if (this.channelListQuery.hasNext && !this.channelListQuery.isLoading) { - this.channelListQuery.next(function(channelList, error) { - if (error) { - console.error(error); - return; - } - action(channelList); - }); - } - } - - getChannelInfo(channelUrl, action) { - this.sb.GroupChannel.getChannel(channelUrl, function(channel, error) { - if (error) { - console.error(error); - return; - } - action(channel); - }); - } - - createNewChannel(userIds, action) { - this.sb.GroupChannel.createChannelWithUserIds(userIds, true, '', '', '', function(channel, error) { - if (error) { - console.error(error); - return; - } - action(channel); - }); - } - - inviteMember(channel, userIds, action) { - channel.inviteWithUserIds(userIds, (response, error) => { - if (error) { - console.error(error); - return; - } - action(); - }); - } - - channelLeave(channel, action) { - channel.leave((response, error) => { - if (error) { - console.error(error); - return; - } - action(); - }); - } - - /* - Message - */ - getTotalUnreadCount(action) { - this.sb.GroupChannel.getTotalUnreadMessageCount((unreadCount) => { - action(unreadCount); - }); - } - - getMessageList(channelSet, action) { - if (!channelSet.query) { - channelSet.query = channelSet.channel.createPreviousMessageListQuery(); - } - if (channelSet.query.hasMore && !channelSet.query.isLoading) { - channelSet.query.load(GET_MESSAGE_LIMIT, false, function(messageList, error){ - if (error) { - console.error(error); - return; - } - action(messageList); - }); - } - } - - sendTextMessage(channel, textMessage, action) { - channel.sendUserMessage(textMessage, (message, error) => { - if (error) { - console.error(error); - return; - } - action(message); - }); - } - - sendFileMessage(channel, file, action) { - let thumbSize = []; - if (file.type.match(/^image\/.+$/)) { - thumbSize = [{'maxWidth': 160, 'maxHeight': 160}]; - } - channel.sendFileMessage(file, '', '', thumbSize, (message, error) => { - if (error) { - console.error(error); - return; - } - action(message); - }); - } - - /* - User - */ - getUserList(action) { - if (!this.userListQuery) { - this.userListQuery = this.sb.createUserListQuery(); - } - if (this.userListQuery.hasNext && !this.userListQuery.isLoading) { - this.userListQuery.next((userList, error) => { - if (error) { - console.error(error); - return; - } - action(userList); - }); - } - } - - /* - Handler - */ - createHandlerGlobal(...args) { - let messageReceivedFunc = args[0]; - let ChannelChangedFunc = args[1]; - let typingStatusFunc = args[2]; - let readReceiptFunc = args[3]; - let userLeftFunc = args[4]; - let userJoinFunc = args[5]; - - let channelHandler = new this.sb.ChannelHandler(); - channelHandler.onMessageReceived = function(channel, message) { - messageReceivedFunc(channel, message); - }; - channelHandler.onChannelChanged = function(channel) { - ChannelChangedFunc(channel); - }; - channelHandler.onTypingStatusUpdated = function(channel) { - typingStatusFunc(channel); - }; - channelHandler.onReadReceiptUpdated = function(channel) { - readReceiptFunc(channel); - }; - channelHandler.onUserLeft = function (channel, user) { - userLeftFunc(channel, user); - }; - channelHandler.onUserJoined = function (channel, user) { - userJoinFunc(channel, user); - }; - this.sb.addChannelHandler(GLOBAL_HANDLER, channelHandler); - } - - /* - Info - */ - getNicknamesString(channel) { - let nicknameList = []; - let currentUserId = this.sb.currentUser.userId; - channel.members.forEach(function(member) { - if (member.userId != currentUserId) { - nicknameList.push(member.nickname); - } - }); - return nicknameList.toString(); - } - - getMemberCount(channel) { - return (channel.memberCount > 9) ? MAX_COUNT : channel.memberCount.toString(); - } - - getLastMessage(channel) { - if (channel.lastMessage) { - return channel.lastMessage.isUserMessage() ? channel.lastMessage.message : channel.lastMessage.name; - } - return ''; - } - - getMessageTime(message) { - const months = [ - 'JAN', 'FEB', 'MAR', 'APR', 'MAY', - 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', - 'NOV', 'DEC' - ]; - - var _getDay = (val) => { - let day = parseInt(val); - if (day == 1) { - return day + 'st'; - } else if (day == 2) { - return day + 'en'; - } else if (day == 3) { - return day + 'rd'; - } else { - return day + 'th'; - } - }; - - var _checkTime = (val) => { - return (+val < 10) ? '0' + val : val; - }; - - if (message) { - const LAST_MESSAGE_YESTERDAY = 'YESTERDAY'; - var _nowDate = new Date(); - var _date = new Date(message.createdAt); - if (_nowDate.getDate() - _date.getDate() == 1) { - return LAST_MESSAGE_YESTERDAY; - } else if (_nowDate.getFullYear() == _date.getFullYear() - && _nowDate.getMonth() == _date.getMonth() - && _nowDate.getDate() == _date.getDate()) { - return _checkTime(_date.getHours()) + ':' + _checkTime(_date.getMinutes()); - } else { - return months[_date.getMonth()] + ' ' + _getDay(_date.getDate()); - } - } - return ''; - } - - getMessageReadReceiptCount(channel, message) { - return channel.getReadReceipt(message); - } - - getChannelUnreadCount(channel) { - return channel.unreadMessageCount; - } - -} - -export { Sendbird as default }; diff --git a/web-widget/src/js/utils.js b/web-widget/src/js/utils.js deleted file mode 100644 index dc107588..00000000 --- a/web-widget/src/js/utils.js +++ /dev/null @@ -1,88 +0,0 @@ -const ANIMATION_EVENT = 'animationend'; -const ANIMATION_REGEX = 'sb-fade.*'; -const DISPLAY_NONE = 'none'; -const DISPLAY_BLOCK = 'block'; - -var hasClassRegex = (target, classNameRegex) => { - return new RegExp('(^| )' + classNameRegex + '( |$)', 'gi').test(target.className); -}; - -export function hide(target) { - if (target) { - if (hasClassRegex(target, ANIMATION_REGEX)) { - let hideAnimationEvent; - target.addEventListener(ANIMATION_EVENT, hideAnimationEvent = function() { - target.style.display = DISPLAY_NONE; - target.removeEventListener(ANIMATION_EVENT, hideAnimationEvent, false); - }); - } else { - target.style.display = DISPLAY_NONE; - } - } -} - -export function show(target, displayType) { - if (target) { - displayType ? target.style.display = displayType : target.style.display = DISPLAY_BLOCK; - } -} - -export function hasClass(...args) { - return args.reduce((target, className) => { - if (target.classList) { - return target.classList.contains(className); - } else { - return new RegExp('(^| )' + className + '( |$)', 'gi').test(target.className); - } - }); - -} - -export function addClass(...args) { - return args.reduce((target, className) => { - if (target.classList) { - if (!(className in target.classList)) { - target.classList.add(className); - } - } else { - if (target.className.indexOf(className) < 0) { - target.className += ' ' + className; - } - } - return target; - }); -} - -export function removeClass(...args) { - return args.reduce((target, className) => { - if (target.classList) { - target.classList.remove(className); - } else { - target.className = target.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ''); - } - return target; - }); -} - -export function isEmptyString(target) { - return !!(target == null || target == undefined || target.length == 0); -} - -export function removeWhiteSpace(target) { - return target.replace(/ /g,''); -} - -export function getFullHeight(target) { - var height = target.offsetHeight; - var style = getComputedStyle(target); - height += parseInt(style.marginTop) + parseInt(style.marginBottom); - return height; -} - -export function insertMessageInList(target, index, item) { - return target.splice(index, 0, item); -} - -export function getLastItem(target) { - return target.length < 1 ? null : target[target.length-1]; -} diff --git a/web-widget/src/js/widget.js b/web-widget/src/js/widget.js deleted file mode 100644 index 7d7223a1..00000000 --- a/web-widget/src/js/widget.js +++ /dev/null @@ -1,748 +0,0 @@ -import WidgetBtn from './elements/widget-btn.js'; -import ListBoard from './elements/list-board.js'; -import ChatSection from './elements/chat-section.js'; -import Popup from './elements/popup.js'; -import Spinner from './elements/spinner.js'; -import Sendbird from './sendbird.js'; -import { hide, show, addClass, removeClass, hasClass, getFullHeight, insertMessageInList, getLastItem, isEmptyString } from './utils.js'; -import { className, TYPE_STRING, MAX_COUNT } from './consts.js'; - -const WIDGET_ID = 'sb_widget'; -const TIME_STRING_TODAY = 'TODAY'; -const TIME_MESSAGE_TYPE = 'time'; -const NEW_CHAT_BOARD_ID = 'NEW_CHAT'; -const KEY_DOWN_ENTER = 13; -const KEY_DOWN_KR = 229; -const CHAT_BOARD_WIDTH = 300; -const ERROR_MESSAGE = 'Please create "sb_widget" element on first.'; -const ERROR_MESSAGE_SDK = 'Please import "SendBird SDK" on first.'; -const EVENT_TYPE_CLICK = 'click'; - -window.WebFontConfig = { - google: { families: ['Lato:400,700'] } -}; - -class SBWidget { - constructor() { - - } - - start(appId) { - if (!window.SendBird) { - console.error(ERROR_MESSAGE_SDK); - return; - } - this._getGoogleFont(); - this.widget = document.getElementById(WIDGET_ID); - if (this.widget) { - document.addEventListener(EVENT_TYPE_CLICK, (event) => { - this._initClickEvent(event) - }); - this._init(); - this._start(appId); - } else { - console.error(ERROR_MESSAGE); - } - } - - startWithConnect(appId, userId, nickname, callback) { - if (!window.SendBird) { - console.error(ERROR_MESSAGE_SDK); - return; - } - this._getGoogleFont(); - this.widget = document.getElementById(WIDGET_ID); - if (this.widget) { - document.addEventListener(EVENT_TYPE_CLICK, (event) => { - this._initClickEvent(event) - }); - this._init(); - this._start(appId); - this._connect(userId, nickname, callback); - } else { - console.error(ERROR_MESSAGE); - } - } - - _initClickEvent(event) { - var _checkPopup = function(_target, obj) { - if (obj === _target || hasClass(_target, className.IC_MEMBERS) || hasClass(_target, className.IC_INVITE)) { - return true; - } else { - var returnedCheck = false; - for (var i = 0 ; i < obj.childNodes.length ; i++) { - returnedCheck = _checkPopup(_target, obj.childNodes[i]); - if (returnedCheck) break; - } - return returnedCheck; - } - }; - - if (!_checkPopup(event.target, this.popup.memberPopup)) { - this.closeMemberPopup(); - } - if (!_checkPopup(event.target, this.popup.invitePopup)) { - this.closeInvitePopup(); - } - } - - _init() { - this.spinner = new Spinner(); - - this.widgetBtn = new WidgetBtn(this.widget); - this.listBoard = new ListBoard(this.widget); - this.chatSection = new ChatSection(this.widget); - this.popup = new Popup(); - - this.activeChannelSetList = []; - this.extraChannelSetList = []; - - this.timeMessage = class TimeMessage { - constructor(date) { - this.time = date; - this.type = TIME_MESSAGE_TYPE; - } - isTimeMessage() { - return this.type == TIME_MESSAGE_TYPE; - } - }; - } - - _getGoogleFont() { - var wf = document.createElement('script'); - wf.src = ('https:' == document.location.protocol ? 'https' : 'http') + - '://ajax.googleapis.com/ajax/libs/webfont/1.5.18/webfont.js'; - wf.type = 'text/javascript'; - wf.async = 'true'; - var s = document.getElementsByTagName('script')[0]; - s.parentNode.insertBefore(wf, s); - } - - reset() { - this.extraChannelSetList = []; - for (var i = 0 ; i < this.activeChannelSetList.length ; i++) { - let channelSet = this.activeChannelSetList[i]; - let targetBoard = this.chatSection.getChatBoard(channelSet.channel.url); - if (targetBoard) { - this.chatSection.closeChatBoard(targetBoard); - } - } - this.activeChannelSetList = []; - this.closePopup(); - - this.sb.reset(); - this.listBoard.reset(); - this.widgetBtn.reset(); - } - - responsiveChatSection(channelUrl, isShow) { - let _bodyWidth = document.getElementsByTagName('BODY')[0].offsetWidth - 360; - let maxSize = parseInt(_bodyWidth / CHAT_BOARD_WIDTH); - let currentSize = this.activeChannelSetList.length; - if (currentSize >= maxSize) { - let extraChannelSet = getLastItem(this.activeChannelSetList); - if (extraChannelSet) { - if (this.extraChannelSetList.indexOf(extraChannelSet.channel.url) < 0) { - this.extraChannelSetList.push(extraChannelSet.channel.url); - } - let chatBoard = this.chatSection.getChatBoard(extraChannelSet.channel.url); - if (chatBoard) { - this.chatSection.closeChatBoard(chatBoard); - } - this.removeChannelSet(extraChannelSet.channel); - } - if (channelUrl) { - let idx = this.extraChannelSetList.indexOf(channelUrl); - if (idx > -1) { - this.extraChannelSetList.splice(idx, 1); - } - } - this.chatSection.setWidth(maxSize * CHAT_BOARD_WIDTH); - } else { - let popChannelUrl = this.extraChannelSetList.pop(); - if (popChannelUrl) { - this._connectChannel(popChannelUrl, true); - this.chatSection.setWidth((currentSize + 1) * CHAT_BOARD_WIDTH); - } else { - if (isShow) { - currentSize += 1; - } - this.chatSection.setWidth(currentSize * CHAT_BOARD_WIDTH); - } - } - } - - _start(appId) { - this.sb = new Sendbird(appId); - - this.popup.addCloseBtnClickEvent(() => { - this.closePopup(); - }); - - this.widgetBtn.addClickEvent(() => { - this.sb.isConnected() ? this.listBoard.showChannelList() : this.listBoard.showLoginForm(); - this.toggleBoard(true); - this.listBoard.addChannelListScrollEvent(() => { - this.getChannelList(); - }); - this.chatSection.responsiveSize(false, this.responsiveChatSection.bind(this)); - }); - - this.listBoard.addNewChatClickEvent(() => { - this.listBoard.hideLogoutBtn(); - - var chatBoard = this.chatSection.createChatBoard(NEW_CHAT_BOARD_ID); - this.responsiveChatSection(null, true); - - this.chatSection.createNewChatBoard(chatBoard); - this.chatSection.addClickEvent(chatBoard.startBtn, () => { - if (!hasClass(chatBoard.startBtn, className.DISABLED)) { - addClass(chatBoard.startBtn, className.DISABLED); - this.sb.userListQuery = null; - this.spinner.insert(chatBoard.startBtn); - let selectedUserIds = this.chatSection.getSelectedUserIds(chatBoard.userContent); - this.sb.createNewChannel(selectedUserIds, (channel) => { - chatBoard.parentNode.removeChild(chatBoard); - this._connectChannel(channel.url, true); - this.listBoard.checkEmptyList(); - }); - } - }); - this.spinner.insert(chatBoard.userContent); - - this.sb.getUserList((userList) => { - this.spinner.remove(chatBoard.userContent); - this.setUserList(chatBoard, userList); - }); - - this.chatSection.addClickEvent(chatBoard.closeBtn, () => { - this.chatSection.closeChatBoard(chatBoard); - this.closePopup(); - this.responsiveChatSection(); - }); - hide(chatBoard.leaveBtn); - hide(chatBoard.memberBtn); - hide(chatBoard.inviteBtn); - }); - - this.listBoard.addMinimizeClickEvent(() => { - this.listBoard.hideLogoutBtn(); - this.closePopup(); - this.toggleBoard(false); - this.chatSection.responsiveSize(true, this.responsiveChatSection.bind(this)); - }); - - this.listBoard.addLogoutClickEvent(() => { - this.sb.disconnect(() => { - this.sb.reset(); - this.toggleBoard(false); - this.widgetBtn.toggleIcon(false); - this.listBoard.setOptionEventLock(false); - this.chatSection.reset(); - this.reset(); - }); - }); - - this.listBoard.addLoginClickEvent(() => { - if (!hasClass(this.listBoard.btnLogin, className.DISABLED)) { - this.spinner.insert(this.listBoard.btnLogin); - this.listBoard.enabledToggle(this.listBoard.btnLogin, false); - this.listBoard.userId.disabled = true; - this.listBoard.nickname.disabled = true; - - this._connect(this.listBoard.getUserId(), this.listBoard.getNickname()); - } - }); - this.listBoard.addKeyDownEvent(this.listBoard.nickname, (event) => { - if (event.keyCode == KEY_DOWN_ENTER) { - this.listBoard.btnLogin.click(); - } - }); - } - - _connect(userId, nickname, callback) { - this.sb.connect(userId, nickname, () => { - this.widgetBtn.toggleIcon(true); - - this.listBoard.showChannelList(); - this.spinner.insert(this.listBoard.list); - this.getChannelList(); - - this.sb.createHandlerGlobal( - (channel, message) => { - this.messageReceivedAction(channel, message); - }, - (channel) => { - this.updateUnreadMessageCount(channel); - }, - (channel) => { - let targetBoard = this.chatSection.getChatBoard(channel.url); - if (targetBoard) { - let isBottom = this.chatSection.isBottom(targetBoard.messageContent, targetBoard.list); - this.chatSection.showTyping(channel, this.spinner); - this.chatSection.responsiveHeight(channel.url); - if (isBottom) { - this.chatSection.scrollToBottom(targetBoard.messageContent); - } - } - }, - (channel) => { - let targetBoard = this.chatSection.getChatBoard(channel.url); - if (targetBoard) { - var channelSet = this.getChannelSet(channel.url); - if (channelSet) { - this.chatSection.updateReadReceipt(channelSet, targetBoard); - } - } - }, - (channel, user) => { - if (this.sb.isCurrentUser(user)) { - let item = this.listBoard.getChannelItem(channel.url); - this.listBoard.list.removeChild(item); - this.listBoard.checkEmptyList(); - } else { - this.listBoard.setChannelTitle(channel.url, this.sb.getNicknamesString(channel)); - this.updateUnreadMessageCount(channel); - let targetChatBoard = this.chatSection.getChatBoard(channel.url); - if (targetChatBoard) { - this.updateChannelInfo(targetChatBoard, channel); - } - } - }, - (channel, user) => { - this.listBoard.setChannelTitle(channel.url, this.sb.getNicknamesString(channel)); - let targetChatBoard = this.chatSection.getChatBoard(channel.url); - if (targetChatBoard) { - this.updateChannelInfo(targetChatBoard, channel); - } - } - ); - - if (callback) callback(); - }); - } - - messageReceivedAction(channel, message) { - let target = this.listBoard.getChannelItem(channel.url); - if (!target) { - target = this.createChannelItem(channel); - this.listBoard.checkEmptyList(); - } - this.listBoard.addListOnFirstIndex(target); - - this.listBoard.setChannelLastMessage(channel.url, message.isFileMessage() ? message.name : message.message); - this.listBoard.setChannelLastMessageTime(channel.url, this.sb.getMessageTime(message)); - - let targetBoard = this.chatSection.getChatBoard(channel.url); - if (targetBoard) { - let isBottom = this.chatSection.isBottom(targetBoard.messageContent, targetBoard.list); - let channelSet = this.getChannelSet(channel.url); - let lastMessage = getLastItem(channelSet.message); - channelSet.message.push(message); - this.setMessageItem(channelSet.channel, targetBoard, [message], false, isBottom, lastMessage); - channel.markAsRead(); - this.updateUnreadMessageCount(channel); - } - } - - setUserList(target, userList) { - let userContent = target.userContent; - this.chatSection.createUserList(userContent); - for (var i = 0 ; i < userList.length ; i++) { - let user = userList[i]; - if (!this.sb.isCurrentUser(user)) { - let item = this.chatSection.createUserListItem(user); - this.chatSection.addClickEvent(item, () => { - hasClass(item.select, className.ACTIVE) ? removeClass(item.select, className.ACTIVE) : addClass(item.select, className.ACTIVE); - let selectedUserCount = this.chatSection.getSelectedUserIds(userContent.list).length; - this.chatSection.updateChatTop(target, selectedUserCount > 9 ? MAX_COUNT : selectedUserCount.toString(), null); - (selectedUserCount > 0) ? removeClass(target.startBtn, className.DISABLED) : addClass(target.startBtn, className.DISABLED); - }); - userContent.list.appendChild(item); - } - } - this.chatSection.addUserListScrollEvent(target, () => { - this.sb.getUserList((userList) => { - this.setUserList(target, userList); - }); - }); - } - - getChannelList() { - let _list = this.listBoard.list; - let _spinner = this.spinner; - this.sb.getChannelList((channelList) => { - if (_list.lastElementChild == _spinner.self) { - _spinner.remove(_list); - } - channelList.forEach((channel) => { - let item = this.createChannelItem(channel); - _list.appendChild(item); - }); - this.updateUnreadMessageCount(); - this.listBoard.checkEmptyList(); - }); - } - - createChannelItem(channel) { - let item = this.listBoard.createChannelItem( - channel.url, - channel.coverUrl, - this.sb.getNicknamesString(channel), - this.sb.getMessageTime(channel.lastMessage), - this.sb.getLastMessage(channel), - this.sb.getChannelUnreadCount(channel) - ); - this.listBoard.addChannelClickEvent(item, () => { - this.closePopup(); - let channelUrl = item.getAttribute('data-channel-url'); - let openChatBoard = this.chatSection.getChatBoard(channelUrl); - if (!openChatBoard) { - var newChat = this.chatSection.getChatBoard(NEW_CHAT_BOARD_ID); - if (newChat) { - this.chatSection.closeChatBoard(newChat); - } - this._connectChannel(channelUrl); - } - }); - return item; - } - - closePopup () { - this.closeMemberPopup(); - this.closeInvitePopup(); - } - - closeMemberPopup() { - this.chatSection.removeMemberPopup(); - this.popup.closeMemberPopup(); - } - - closeInvitePopup() { - this.chatSection.removeInvitePopup(); - this.popup.closeInvitePopup(); - this.sb.userListQuery = null; - } - - showChannel(channelUrl) { - this._connectChannel(channelUrl, false); - } - - _connectChannel(channelUrl, doNotCall) { - var chatBoard = this.chatSection.createChatBoard(channelUrl, doNotCall); - if (!doNotCall) { - this.responsiveChatSection(channelUrl, true); - } - this.chatSection.addClickEvent(chatBoard.closeBtn, () => { - this.chatSection.closeChatBoard(chatBoard); - this.closePopup(); - this.removeChannelSet(channelUrl); - this.responsiveChatSection(); - }); - this.chatSection.addClickEvent(chatBoard.leaveBtn, () => { - this.chatSection.addLeavePopup(chatBoard); - this.chatSection.setLeaveBtnClickEvent(chatBoard.leavePopup.leaveBtn, () => { - this.spinner.insert(chatBoard.leavePopup.leaveBtn); - addClass(chatBoard.leavePopup.leaveBtn, className.DISABLED); - let channelSet = this.getChannelSet(channelUrl); - if (channelSet) { - this.sb.channelLeave(channelSet.channel, () => { - chatBoard.removeChild(chatBoard.leavePopup); - removeClass(chatBoard.leavePopup.leaveBtn, className.DISABLED); - chatBoard.leavePopup = null; - chatBoard.closeBtn.click(); - }); - } else { - this.chatSection.closeChatBoard(chatBoard); - } - }); - }); - this.chatSection.addClickEvent(chatBoard.memberBtn, () => { - if (hasClass(chatBoard.memberBtn, className.ACTIVE)) { - this.closeMemberPopup(); - } else { - this.closeMemberPopup(); - this.closeInvitePopup(); - addClass(chatBoard.memberBtn, className.ACTIVE); - let index = this.chatSection.indexOfChatBord(channelUrl); - this.popup.showMemberPopup(this.chatSection.self, index); - let channelSet = this.getChannelSet(channelUrl); - this.popup.updateCount(this.popup.memberPopup.count, channelSet.channel.memberCount); - for (var i = 0 ; i < channelSet.channel.members.length ; i++) { - let member = channelSet.channel.members[i]; - let item = this.popup.createMemberItem(member, false, this.sb.isCurrentUser(member)); - this.popup.memberPopup.list.appendChild(item); - } - } - }); - this.chatSection.addClickEvent(chatBoard.inviteBtn, () => { - var _getUserList = (memberIds, loadmore) => { - this.sb.getUserList((userList) => { - if (!loadmore) { - this.spinner.remove(this.popup.invitePopup.list); - } - for (var i = 0 ; i < userList.length ; i++) { - let user = userList[i]; - if (memberIds.indexOf(user.userId) < 0) { - let item = this.popup.createMemberItem(user, true); - this.popup.addClickEvent(item, () => { - hasClass(item.select, className.ACTIVE) ? removeClass(item.select, className.ACTIVE) : addClass(item.select, className.ACTIVE); - let selectedUserCount = this.popup.getSelectedUserIds(this.popup.invitePopup.list).length; - this.popup.updateCount(this.popup.invitePopup.count, selectedUserCount); - (selectedUserCount > 0) ? removeClass(this.popup.invitePopup.inviteBtn, className.DISABLED) : addClass(this.popup.invitePopup.inviteBtn, className.DISABLED); - }); - this.popup.invitePopup.list.appendChild(item); - } - } - }); - }; - - if (hasClass(chatBoard.inviteBtn, className.ACTIVE)) { - this.closeInvitePopup(); - } else { - this.closeInvitePopup(); - this.closeMemberPopup(); - addClass(chatBoard.inviteBtn, className.ACTIVE); - let index = this.chatSection.indexOfChatBord(channelUrl); - this.popup.showInvitePopup(this.chatSection.self, index); - this.spinner.insert(this.popup.invitePopup.list); - let channelSet = this.getChannelSet(channelUrl); - let memberIds = channelSet.channel.members.map((member) => { - return member.userId; - }); - _getUserList(memberIds); - - this.popup.addClickEvent(this.popup.invitePopup.inviteBtn, () => { - if (!hasClass(this.popup.invitePopup.inviteBtn, className.DISABLED)) { - addClass(this.popup.invitePopup.inviteBtn, className.DISABLED); - this.spinner.insert(this.popup.invitePopup.inviteBtn); - let selectedUserIds = this.popup.getSelectedUserIds(this.popup.invitePopup.list); - let channelSet = this.getChannelSet(channelUrl); - this.sb.inviteMember(channelSet.channel, selectedUserIds, () => { - this.spinner.remove(this.popup.invitePopup.inviteBtn); - this.closeInvitePopup(); - this.listBoard.setChannelTitle(channelSet.channel.url, this.sb.getNicknamesString(channelSet.channel)); - this.updateChannelInfo(chatBoard, channelSet.channel); - }); - } - }); - - this.popup.addScrollEvent(() => { - _getUserList(memberIds, true); - }); - } - }); - this.spinner.insert(chatBoard.content); - this.sb.getChannelInfo(channelUrl, (channel) => { - this.updateChannelInfo(chatBoard, channel); - let channelSet = this.getChannelSet(channel); - this.getMessageList(channelSet, chatBoard, false, () => { - this.chatScrollEvent(chatBoard, channelSet); - }); - channel.markAsRead(); - this.updateUnreadMessageCount(channel); - - let listItem = this.listBoard.getChannelItem(channelUrl); - if (!listItem) { - listItem = this.createChannelItem(channel); - this.listBoard.list.insertBefore(listItem, this.listBoard.list.firstChild); - } - }); - } - - updateChannelInfo(target, channel) { - this.chatSection.updateChatTop( - target, this.sb.getMemberCount(channel), this.sb.getNicknamesString(channel) - ); - } - - updateUnreadMessageCount(channel) { - this.sb.getTotalUnreadCount((unreadCount) => { - this.widgetBtn.setUnreadCount(unreadCount); - }); - - if (channel) { - this.listBoard.setChannelUnread(channel.url, channel.unreadMessageCount); - } - } - - getMessageList(channelSet, target, loadmore, scrollEvent) { - this.sb.getMessageList(channelSet, (messageList) => { - let messageItems = messageList.slice(); - let tempTime; - for (var index = 0 ; index < messageList.length ; index++) { - let message = messageList[index]; - loadmore ? channelSet.message.unshift(message) : channelSet.message.push(message); - - let time = this.sb.getMessageTime(message); - if (time.indexOf(':') > -1) { - time = TIME_STRING_TODAY; - } - if (tempTime != time) { - tempTime = time; - insertMessageInList(messageItems, messageItems.indexOf(message), new this.timeMessage(time)); - } - } - - let scrollToBottom = false; - if (!loadmore) { - if (tempTime != TIME_STRING_TODAY) { - messageItems.push(new this.timeMessage(TIME_STRING_TODAY)); - } - scrollToBottom = true; - this.spinner.remove(target.content); - this.chatSection.createMessageContent(target); - this.chatSection.addFileSelectEvent(target.file, () => { - let file = target.file.files[0]; - this.sb.sendFileMessage(channelSet.channel, file, (message) => { - this.messageReceivedAction(channelSet.channel, message); - }); - }); - this.chatSection.addKeyDownEvent(target.input, (event) => { - if(event.keyCode == KEY_DOWN_KR) { - this.chatSection.textKr = target.input.textContent; - } - - if (event.keyCode == KEY_DOWN_ENTER && !event.shiftKey) { - let textMessage = target.input.textContent || this.chatSection.textKr; - if (!isEmptyString(textMessage.trim())) { - this.sb.sendTextMessage(channelSet.channel, textMessage, (message) => { - this.messageReceivedAction(channelSet.channel, message); - }); - } - this.chatSection.clearInputText(target.input, channelSet.channel.url); - this.chatSection.textKr = ''; - channelSet.channel.endTyping(); - } else { - channelSet.channel.startTyping(); - } - this.chatSection.responsiveHeight(channelSet.channel.url); - }); - this.chatSection.addKeyUpEvent(target.input, (event) => { - let isBottom = this.chatSection.isBottom(target.messageContent, target.list); - this.chatSection.responsiveHeight(channelSet.channel.url); - if (event.keyCode == KEY_DOWN_ENTER && !event.shiftKey) { - this.chatSection.clearInputText(target.input, channelSet.channel.url); - if (isBottom) { - this.chatSection.scrollToBottom(target.messageContent); - } - } - }); - this.chatSection.addPasteEvent(target.input, (event) => { - var clipboardData; - var pastedData; - - event.stopPropagation(); - event.preventDefault(); - - clipboardData = event.clipboardData || window.clipboardData; - pastedData = clipboardData.getData('Text'); - - target.input.textContent += pastedData; - }); - } - if (scrollEvent) { - scrollEvent(); - } - this.setMessageItem(channelSet.channel, target, messageItems, loadmore, scrollToBottom); - }); - } - - setMessageItem(channel, target, messageList, loadmore, scrollToBottom, lastMessage) { - let firstChild = target.list.firstChild; - let addScrollHeight = 0; - let prevMessage; - let newMessage; - if (lastMessage && messageList[0] && !messageList[0].isTimeMessage) { - prevMessage = lastMessage; - } - for (var i = 0 ; i < messageList.length ; i++) { - let message = messageList[i]; - if (message.isTimeMessage && message.isTimeMessage()) { - newMessage = this.chatSection.createMessageItemTime(message.time); - prevMessage = null; - } else { - let isContinue = false; - if (message.isAdminMessage()) { - newMessage = this.chatSection.createAdminMessageItem(message); - } else { // isUserMessage() || isFileMessage() - isContinue = (prevMessage && prevMessage.sender) ? (message.sender.userId == prevMessage.sender.userId) : false; - let isCurrentUser = this.sb.isCurrentUser(message.sender); - let unreadCount = channel.getReadReceipt(message); - if (message.isUserMessage()) { - newMessage = this.chatSection.createMessageItem(message, isCurrentUser, isContinue, unreadCount); - } else if (message.isFileMessage()) { - newMessage = this.chatSection.createMessageItem(message, isCurrentUser, isContinue, unreadCount); - } - } - prevMessage = message; - } - - if (loadmore) { - target.list.insertBefore(newMessage, firstChild); - addScrollHeight += getFullHeight(newMessage); - } else { - target.list.appendChild(newMessage); - } - } - - if(loadmore) { - target.messageContent.scrollTop = addScrollHeight; - } else if (scrollToBottom) { - this.chatSection.scrollToBottom(target.messageContent); - } - } - - chatScrollEvent(target, channelSet) { - this.chatSection.addScrollEvent(target.messageContent, () => { - if (target.messageContent.scrollTop == 0) { - this.getMessageList(channelSet, target, true); - } - }); - } - - getChannelSet(channel, isLast) { - let isObject = true; - if (typeof channel === TYPE_STRING || channel instanceof String) { - isObject = false; - } - - let channelSet = this.activeChannelSetList.filter((obj) => { - return isObject ? obj.channel == channel : obj.channel.url == channel; - })[0]; - - if (!channelSet && isObject) { - channelSet = { - 'channel': channel, - 'query': channel.createPreviousMessageListQuery(), - 'message': [] - }; - isLast ? this.activeChannelSetList.push(channelSet) : this.activeChannelSetList.unshift(channelSet); - } - - return channelSet; - } - - removeChannelSet(channel) { - let isObject = true; - if (typeof channel === TYPE_STRING || channel instanceof String) { - isObject = false; - } - - this.activeChannelSetList = this.activeChannelSetList.filter(function(obj) { - return isObject ? obj.channel != channel : obj.channel.url != channel; - }); - } - - toggleBoard(isShow) { - if (isShow) { - hide(addClass(removeClass(this.widgetBtn.self, className.FADE_IN), className.FADE_OUT)); - show(addClass(removeClass(this.listBoard.self, className.FADE_OUT), className.FADE_IN)); - } else { - hide(addClass(removeClass(this.listBoard.self, className.FADE_IN), className.FADE_OUT)); - show(addClass(removeClass(this.widgetBtn.self, className.FADE_OUT), className.FADE_IN)); - } - } -} - -window.sbWidget = new SBWidget(); diff --git a/web-widget/src/scss/mixins/_state.scss b/web-widget/src/scss/mixins/_state.scss deleted file mode 100644 index c1203da1..00000000 --- a/web-widget/src/scss/mixins/_state.scss +++ /dev/null @@ -1,40 +0,0 @@ -@mixin hover { - &:hover { @content; } -} - -@mixin plain-hover { - &, - &:hover { @content; } -} - -@mixin focus { - &:focus { @content; } -} - -@mixin plain-focus { - &, - &:focus { @content; } -} - -@mixin hover-focus { - &:hover, - &:focus { @content; } -} - -@mixin plain-hover-focus { - &, - &:hover, - &:focus { @content; } -} - -@mixin after { - &::after { - @content - } -} - -@mixin before { - &::before { - @content - } -} diff --git a/web-widget/webpack.config.js b/web-widget/webpack.config.js deleted file mode 100644 index 532bf9a6..00000000 --- a/web-widget/webpack.config.js +++ /dev/null @@ -1,51 +0,0 @@ -module.exports = { - context: __dirname + '/src', - entry: { - widget: ['babel-polyfill', './js/widget.js'] - }, - output: { - path: __dirname + '/build', - filename: '[name].SendBird.js' - }, - module: { - rules: [ - { // SCSS - test: /\.scss$/, - use: [ - { - loader: 'style-loader' - }, - { - loader: 'css-loader' - }, - { - loader: 'sass-loader' - } - ] - }, - { // ESLint - enforce: 'pre', - test: /\.js$/, - exclude: /(node_modules|SendBird.min.js)/, - use: [ - { - loader: 'eslint-loader', - options: { - failOnError: true - } - } - ] - }, - { // ES6 - test: /\.js$/, - exclude: /(node_modules)/, - use: { - loader: 'babel-loader', - options: { - presets: ['env', 'es2015'] - } - } - } - ] - } -};