diff options
121 files changed, 1861 insertions, 1636 deletions
@@ -308,7 +308,12 @@ stop-client: done @for PID in $$(ps -ef | grep [n]pm | awk '{ print $$2 }'); do \ - echo stopping watchify $$PID; \ + echo stopping client $$PID; \ + kill $$PID; \ + done + + @for PID in $$(ps -ef | grep [w]atchify | awk '{ print $$2 }'); do \ + echo stopping client $$PID; \ kill $$PID; \ done diff --git a/api/templates/error.html b/api/templates/error.html index 2b6211be2..2f588aead 100644 --- a/api/templates/error.html +++ b/api/templates/error.html @@ -1,7 +1,7 @@ <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> - <title>{{ .ClientCfg.SiteName }} - Error</title> + <title><span class='fa fa-chevron-left'></span>Back - Error</title> <link rel="stylesheet" href="/static/css/bootstrap-3.3.5.min.css"> <link rel="stylesheet" href="/static/css/jasny-bootstrap.min.css" rel="stylesheet"> diff --git a/i18n/en.json b/i18n/en.json index f45f65526..759e3ff9a 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -2360,6 +2360,10 @@ "translation": "Failed to create index %v" }, { + "id": "store.sql.remove_index.critical", + "translation": "Failed to remove index %v" + }, + { "id": "store.sql.create_index_missing_driver.critical", "translation": "Failed to create index because of missing driver" }, @@ -2404,6 +2408,14 @@ "translation": "Failed to rename column %v" }, { + "id": "store.sql.alter_column_type.critical", + "translation": "Failed to alter column type %v" + }, + { + "id": "store.sql.maxlength_column.critical", + "translation": "Failed to get max length of column %v" + }, + { "id": "store.sql.schema_out_of_date.warn", "translation": "The database schema version of %v appears to be out of date" }, @@ -3356,6 +3368,10 @@ "translation": "Find Team" }, { + "id": "web.header.back", + "translation": "Back" + }, + { "id": "web.footer.about", "translation": "About" }, diff --git a/i18n/es.json b/i18n/es.json index bcb254332..c705c0fa7 100644 --- a/i18n/es.json +++ b/i18n/es.json @@ -1617,7 +1617,7 @@ }, { "id": "api.web_hub.start.stopping.debug", - "translation": "deteniendo todas las conexiones" + "translation": "deteniendo conexiones %v" }, { "id": "api.web_socket.connect.error", @@ -3356,6 +3356,10 @@ "translation": "Encontrar Equipo" }, { + "id": "web.header.back", + "translation": "Atrás" + }, + { "id": "web.footer.about", "translation": "Acerca" }, diff --git a/store/sql_post_store.go b/store/sql_post_store.go index dfb9563eb..6a614b6a7 100644 --- a/store/sql_post_store.go +++ b/store/sql_post_store.go @@ -38,10 +38,10 @@ func NewSqlPostStore(sqlStore *SqlStore) PostStore { } func (s SqlPostStore) UpgradeSchemaIfNeeded() { - // ADDED for 1.3 REMOVE for 1.6 + // ADDED for 1.3 REMOVE for 2.2 s.RemoveColumnIfExists("Posts", "ImgCount") - // ADDED for 1.3 REMOVE for 1.6 + // ADDED for 1.3 REMOVE for 2.2 s.GetMaster().Exec(`UPDATE Preferences SET Type = :NewType WHERE Type = :CurrentType`, map[string]string{"NewType": model.POST_JOIN_LEAVE, "CurrentType": "join_leave"}) } diff --git a/store/sql_session_store.go b/store/sql_session_store.go index 6532947f4..8dccc0770 100644 --- a/store/sql_session_store.go +++ b/store/sql_session_store.go @@ -22,7 +22,7 @@ func NewSqlSessionStore(sqlStore *SqlStore) SessionStore { table.ColMap("Token").SetMaxSize(26) table.ColMap("UserId").SetMaxSize(26) table.ColMap("TeamId").SetMaxSize(26) - table.ColMap("DeviceId").SetMaxSize(128) + table.ColMap("DeviceId").SetMaxSize(512) table.ColMap("Roles").SetMaxSize(64) table.ColMap("Props").SetMaxSize(1000) } @@ -31,6 +31,11 @@ func NewSqlSessionStore(sqlStore *SqlStore) SessionStore { } func (me SqlSessionStore) UpgradeSchemaIfNeeded() { + // ADDED for 2.1 REMOVE for 2.5 + deviceIdLength := me.GetMaxLengthOfColumnIfExists("Sessions", "DeviceId") + if len(deviceIdLength) > 0 && deviceIdLength != "512" { + me.AlterColumnTypeIfExists("Sessions", "DeviceId", "VARCHAR(512)", "VARCHAR(512)") + } } func (me SqlSessionStore) CreateIndexesIfNotExists() { @@ -239,7 +244,7 @@ func (me SqlSessionStore) UpdateDeviceId(id, deviceId string) StoreChannel { go func() { result := StoreResult{} if _, err := me.GetMaster().Exec("UPDATE Sessions SET DeviceId = :DeviceId WHERE Id = :Id", map[string]interface{}{"DeviceId": deviceId, "Id": id}); err != nil { - result.Err = model.NewLocAppError("SqlSessionStore.UpdateDeviceId", "store.sql_session.update_device_id.app_error", nil, "") + result.Err = model.NewLocAppError("SqlSessionStore.UpdateDeviceId", "store.sql_session.update_device_id.app_error", nil, err.Error()) } else { result.Data = deviceId } diff --git a/store/sql_store.go b/store/sql_store.go index a994ec57e..de23f4db3 100644 --- a/store/sql_store.go +++ b/store/sql_store.go @@ -139,7 +139,7 @@ func NewSqlStore() Store { sqlStore.preference.(*SqlPreferenceStore).DeleteUnusedFeatures() - if model.IsPreviousVersionsSupported(schemaVersion) { + if model.IsPreviousVersionsSupported(schemaVersion) && !model.IsCurrentVersion(schemaVersion) { sqlStore.system.Update(&model.System{Name: "Version", Value: model.CurrentVersion}) l4g.Warn(utils.T("store.sql.upgraded.warn"), model.CurrentVersion) } @@ -379,6 +379,49 @@ func (ss SqlStore) RenameColumnIfExists(tableName string, oldColumnName string, return true } +func (ss SqlStore) GetMaxLengthOfColumnIfExists(tableName string, columnName string) string { + if !ss.DoesColumnExist(tableName, columnName) { + return "" + } + + var result string + var err error + if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_MYSQL { + result, err = ss.GetMaster().SelectStr("SELECT CHARACTER_MAXIMUM_LENGTH FROM information_schema.columns WHERE table_name = '" + tableName + "' AND COLUMN_NAME = '" + columnName + "'") + } else if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_POSTGRES { + result, err = ss.GetMaster().SelectStr("SELECT character_maximum_length FROM information_schema.columns WHERE table_name = '" + strings.ToLower(tableName) + "' AND column_name = '" + strings.ToLower(columnName) + "'") + } + + if err != nil { + l4g.Critical(utils.T("store.sql.maxlength_column.critical"), err) + time.Sleep(time.Second) + panic(fmt.Sprintf(utils.T("store.sql.maxlength_column.critical"), err.Error())) + } + + return result +} + +func (ss SqlStore) AlterColumnTypeIfExists(tableName string, columnName string, mySqlColType string, postgresColType string) bool { + if !ss.DoesColumnExist(tableName, columnName) { + return false + } + + var err error + if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_MYSQL { + _, err = ss.GetMaster().Exec("ALTER TABLE " + tableName + " MODIFY " + columnName + " " + mySqlColType) + } else if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_POSTGRES { + _, err = ss.GetMaster().Exec("ALTER TABLE " + strings.ToLower(tableName) + " ALTER COLUMN " + strings.ToLower(columnName) + " TYPE " + postgresColType) + } + + if err != nil { + l4g.Critical(utils.T("store.sql.alter_column_type.critical"), err) + time.Sleep(time.Second) + panic(fmt.Sprintf(utils.T("store.sql.alter_column_type.critical"), err.Error())) + } + + return true +} + func (ss SqlStore) CreateIndexIfNotExists(indexName string, tableName string, columnName string) { ss.createIndexIfNotExists(indexName, tableName, columnName, INDEX_TYPE_DEFAULT) } @@ -440,25 +483,66 @@ func (ss SqlStore) createIndexIfNotExists(indexName string, tableName string, co } } +func (ss SqlStore) RemoveIndexIfExists(indexName string, tableName string) { + + if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_POSTGRES { + _, err := ss.GetMaster().SelectStr("SELECT $1::regclass", indexName) + // It should fail if the index does not exist + if err == nil { + return + } + + _, err = ss.GetMaster().Exec("DROP INDEX " + indexName) + if err != nil { + l4g.Critical(utils.T("store.sql.remove_index.critical"), err) + time.Sleep(time.Second) + panic(fmt.Sprintf(utils.T("store.sql.remove_index.critical"), err.Error())) + } + } else if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_MYSQL { + + count, err := ss.GetMaster().SelectInt("SELECT COUNT(0) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = DATABASE() and table_name = ? AND index_name = ?", tableName, indexName) + if err != nil { + l4g.Critical(utils.T("store.sql.check_index.critical"), err) + time.Sleep(time.Second) + panic(fmt.Sprintf(utils.T("store.sql.check_index.critical"), err.Error())) + } + + if count > 0 { + return + } + + _, err = ss.GetMaster().Exec("DROP INDEX " + indexName + " ON " + tableName) + if err != nil { + l4g.Critical(utils.T("store.sql.remove_index.critical"), err) + time.Sleep(time.Second) + panic(fmt.Sprintf(utils.T("store.sql.remove_index.critical"), err.Error())) + } + } else { + l4g.Critical(utils.T("store.sql.create_index_missing_driver.critical")) + time.Sleep(time.Second) + panic(utils.T("store.sql.create_index_missing_driver.critical")) + } +} + func IsUniqueConstraintError(err string, mysql string, postgres string) bool { unique := strings.Contains(err, "unique constraint") || strings.Contains(err, "Duplicate entry") field := strings.Contains(err, mysql) || strings.Contains(err, postgres) return unique && field } -func (ss SqlStore) GetColumnDataType(tableName, columnName string) string { - dataType, err := ss.GetMaster().SelectStr("SELECT data_type FROM INFORMATION_SCHEMA.COLUMNS where table_name = :Tablename AND column_name = :Columnname", map[string]interface{}{ - "Tablename": tableName, - "Columnname": columnName, - }) - if err != nil { - l4g.Critical(utils.T("store.sql.table_column_type.critical"), columnName, tableName, err.Error()) - time.Sleep(time.Second) - panic(fmt.Sprintf(utils.T("store.sql.table_column_type.critical"), columnName, tableName, err.Error())) - } +// func (ss SqlStore) GetColumnDataType(tableName, columnName string) string { +// dataType, err := ss.GetMaster().SelectStr("SELECT data_type FROM INFORMATION_SCHEMA.COLUMNS where table_name = :Tablename AND column_name = :Columnname", map[string]interface{}{ +// "Tablename": tableName, +// "Columnname": columnName, +// }) +// if err != nil { +// l4g.Critical(utils.T("store.sql.table_column_type.critical"), columnName, tableName, err.Error()) +// time.Sleep(time.Second) +// panic(fmt.Sprintf(utils.T("store.sql.table_column_type.critical"), columnName, tableName, err.Error())) +// } - return dataType -} +// return dataType +// } func (ss SqlStore) GetMaster() *gorp.DbMap { return ss.master diff --git a/store/sql_store_test.go b/store/sql_store_test.go index 1be87dec9..474a68ac7 100644 --- a/store/sql_store_test.go +++ b/store/sql_store_test.go @@ -85,3 +85,63 @@ func TestEncrypt(t *testing.T) { t.Fatal("error in encrypt") } } + +func TestAlertDbCmds(t *testing.T) { + Setup() + + sqlStore := store.(*SqlStore) + + if !sqlStore.DoesTableExist("Systems") { + t.Fatal("Failed table exists") + } + + if sqlStore.DoesColumnExist("Systems", "Test") { + t.Fatal("Column should not exist") + } + + if !sqlStore.CreateColumnIfNotExists("Systems", "Test", "VARCHAR(50)", "VARCHAR(50)", "") { + t.Fatal("Failed to create column") + } + + maxLen := sqlStore.GetMaxLengthOfColumnIfExists("Systems", "Test") + + if maxLen != "50" { + t.Fatal("Failed to get max length found " + maxLen) + } + + if !sqlStore.AlterColumnTypeIfExists("Systems", "Test", "VARCHAR(25)", "VARCHAR(25)") { + t.Fatal("failed to alter column size") + } + + maxLen2 := sqlStore.GetMaxLengthOfColumnIfExists("Systems", "Test") + + if maxLen2 != "25" { + t.Fatal("Failed to get max length") + } + + if !sqlStore.RenameColumnIfExists("Systems", "Test", "Test1", "VARCHAR(25)") { + t.Fatal("Failed to rename column") + } + + if sqlStore.DoesColumnExist("Systems", "Test") { + t.Fatal("Column should not exist") + } + + if !sqlStore.DoesColumnExist("Systems", "Test1") { + t.Fatal("Column should exist") + } + + sqlStore.CreateIndexIfNotExists("idx_systems_test1", "Systems", "Test1") + sqlStore.RemoveIndexIfExists("idx_systems_test1", "Systems") + + sqlStore.CreateFullTextIndexIfNotExists("idx_systems_test1", "Systems", "Test1") + sqlStore.RemoveIndexIfExists("idx_systems_test1", "Systems") + + if !sqlStore.RemoveColumnIfExists("Systems", "Test1") { + t.Fatal("Failed to remove columns") + } + + if sqlStore.DoesColumnExist("Systems", "Test1") { + t.Fatal("Column should not exist") + } +} diff --git a/store/sql_user_store.go b/store/sql_user_store.go index d866f949a..47c6ea61a 100644 --- a/store/sql_user_store.go +++ b/store/sql_user_store.go @@ -46,7 +46,7 @@ func NewSqlUserStore(sqlStore *SqlStore) UserStore { } func (us SqlUserStore) UpgradeSchemaIfNeeded() { - // ADDED for 1.5 REMOVE for 1.8 + // ADDED for 2.0 REMOVE for 2.4 us.CreateColumnIfNotExists("Users", "Locale", "varchar(5)", "character varying(5)", model.DEFAULT_LOCALE) } diff --git a/web/react/.eslintrc b/web/react/.eslintrc deleted file mode 100644 index 013175567..000000000 --- a/web/react/.eslintrc +++ /dev/null @@ -1,204 +0,0 @@ -{ - "extends": "eslint:recommended", - "ecmaFeatures": { - "jsx": true, - "blockBindings": true, - "modules": true, - "classes": true, - "arrowFunctions": true, - "defaultParams": true - }, - "parser": "babel-eslint", - "plugins": [ - "react" - ], - "env": { - "browser": true, - "node": true, - "jquery": true, - "es6": true - }, - "globals": { - "React": false, - "ReactDOM": false, - "ReactBootstrap": false, - "ReactIntl": false, - "ReactIntlLocaleData": false, - "Chart": false, - "katex": false - }, - "rules": { - "comma-dangle": [2, "never"], - "no-arrow-condition": 2, - "no-case-declarations": 2, - "no-cond-assign": [2, "except-parens"], - "no-console": 2, - "no-constant-condition": 2, - "no-debugger": 2, - "no-dupe-args": 2, - "no-dupe-keys": 2, - "no-duplicate-case": 2, - "no-empty": 2, - "no-empty-pattern": 2, - "no-ex-assign": 2, - "no-extra-semi": 2, - "no-fallthrough": 2, - "no-func-assign": 2, - "no-inner-declarations": 0, - "no-invalid-regexp": 2, - "no-irregular-whitespace": 2, - "no-unexpected-multiline": 2, - "no-unreachable": 2, - "no-magic-numbers": [1, { "ignore": [-1, 0, 1, 2], "enforceConst": true, "detectObjects": true } ], - "valid-typeof": 2, - - "block-scoped-var": 2, - "complexity": [0, 8], - "consistent-return": 2, - "curly": [2, "all"], - "dot-location": [2, "object"], - "dot-notation": 2, - "eqeqeq": [2, "smart"], - "global-require": 2, - "guard-for-in": 2, - "no-alert": 2, - "no-array-constructor": 2, - "no-caller": 2, - "no-div-regex": 2, - "no-else-return": 2, - "no-eval": 2, - "no-extend-native": 2, - "no-extra-bind": 2, - "no-floating-decimal": 2, - "no-implied-eval": 2, - "no-iterator": 2, - "no-labels": 2, - "no-lone-blocks": 2, - "no-loop-func": 2, - "no-multi-spaces": [2, { "exceptions": { "Property": false } }], - "no-multi-str": 0, - "no-native-reassign": 2, - "no-new": 2, - "no-new-func": 2, - "no-new-object": 2, - "no-new-wrappers": 2, - "no-octal-escape": 2, - "no-param-reassign": 2, - "no-process-env": 2, - "no-process-exit": 2, - "no-proto": 2, - "no-redeclare": 2, - "no-return-assign": [2, "always"], - "no-script-url": 2, - "no-self-compare": 2, - "no-sequences": 2, - "no-throw-literal": 2, - "no-undef-init": 2, - "no-unused-expressions": 2, - "no-useless-concat": 1, - "no-void": 2, - "no-warning-comments": 1, - "no-with": 2, - "radix": 2, - "vars-on-top": 0, - "wrap-iife": [2, "outside"], - "yoda": [2, "never", {"exceptRange": false, "onlyEquality": false}], - - "no-undefined": 2, - "no-shadow": [2, {"hoist": "functions"}], - "no-shadow-restricted-names": 2, - "no-unused-vars": [2, {"vars": "all", "args": "after-used"}], - "no-use-before-define": [2, "nofunc"], - - // Style - "array-bracket-spacing": [2, "never"], - "brace-style": [2, "1tbs", { "allowSingleLine": false }], - "camelcase": [2, {"properties": "never"}], - "comma-spacing": [2, {"before": false, "after": true}], - "comma-style": [2, "last"], - "computed-property-spacing": [2, "never"], - "consistent-this": [2, "self"], - "func-names": 2, - "func-style": [2, "declaration"], - "indent": [2, 4, {"SwitchCase": 0}], - "jsx-quotes": [2, "prefer-single"], - "key-spacing": [2, {"beforeColon": false, "afterColon": true}], - "linebreak-style": 2, - "lines-around-comment": [2, { "beforeBlockComment": true, "beforeLineComment": true, "allowBlockStart": true, "allowBlockEnd": true }], - "new-cap": 2, - "new-parens": 2, - "no-lonely-if": 2, - "no-mixed-spaces-and-tabs": 2, - "no-multiple-empty-lines": [2, {"max": 1}], - "no-negated-condition": 2, - "no-nested-ternary": 2, - "no-spaced-func": 2, - "no-ternary": 0, - "no-trailing-spaces": [2, { "skipBlankLines": false }], - "no-underscore-dangle": 2, - "no-unneeded-ternary": [2, {"defaultAssignment": false}], - "object-curly-spacing": [2, "never"], - "one-var": [2, "never"], - "operator-linebreak": [2, "after"], - "padded-blocks": [2, "never"], - "quote-props": [2, "as-needed"], - "quotes": [2, "single", "avoid-escape"], - "semi": [2, "always"], - "semi-spacing": [2, {"before": false, "after": true}], - "space-after-keywords": [2, "always"], - "space-before-blocks": [2, "always"], - "space-before-function-paren": [2, "never"], - "space-before-keywords": [2, "always"], - "space-in-parens": [2, "never"], - "space-infix-ops": 2, - "space-return-throw-case": 2, - "space-unary-ops": [2, { "words": true, "nonwords": false }], - "wrap-regex": 2, - - // ES6 stuff - "arrow-parens": [2, "always"], - "arrow-body-style": 0, - "arrow-spacing": [2, { "before": true, "after": true }], - "constructor-super": 2, - "generator-star-spacing": [2, {"before": false, "after": true}], - "no-class-assign": 2, - "no-const-assign": 2, - "no-dupe-class-members": 2, - "no-this-before-super": 2, - "no-var": 0, - "object-shorthand": [1, "always"], - "prefer-arrow-callback": 1, - "prefer-const": 1, - "prefer-spread": 2, - "prefer-reflect": 1, - "prefer-template": 0, - "require-yield": 2, - - // React Specific - "react/display-name": [2, { "acceptTranspilerName": true }], - "react/jsx-boolean-value": [2, "always"], - "react/jsx-closing-bracket-location": [2, { "location": "tag-aligned" }], - "react/jsx-curly-spacing": [2, "never"], - "react/jsx-indent-props": [2, 4], - "react/jsx-key": 2, - "react/jsx-max-props-per-line": [2, { "maximum": 1 }], - "react/jsx-no-bind": 1, - "react/jsx-no-duplicate-props": [2, { "ignoreCase": false }], - "react/jsx-no-literals": 1, - "react/jsx-no-undef": 2, - "react/jsx-uses-react": 2, - "react/jsx-uses-vars": 2, - "react/no-danger": 0, - "react/no-did-mount-set-state": 2, - "react/no-did-update-set-state": 2, - "react/no-direct-mutation-state": 2, - "react/no-multi-comp": [2, { "ignoreStateless": true }], - "react/no-set-state": 0, - "react/no-unknown-property": 2, - "react/prefer-es6-class": 2, - "react/prop-types": 2, - "react/self-closing-comp": 2, - "react/sort-comp": 0, - "react/wrap-multilines": 2 - } -} diff --git a/web/react/.eslintrc.json b/web/react/.eslintrc.json new file mode 100644 index 000000000..51345113b --- /dev/null +++ b/web/react/.eslintrc.json @@ -0,0 +1,226 @@ +{ + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module", + "ecmaFeatures": { + "jsx": true, + "impliedStrict": true, + "modules": true + } + }, + "parser": "babel-eslint", + "plugins": [ + "react" + ], + "env": { + "browser": true, + "node": true, + "jquery": true, + "es6": true + }, + "globals": { + "React": false, + "ReactDOM": false, + "ReactBootstrap": false, + "ReactIntl": false, + "ReactIntlLocaleData": false, + "Chart": false, + "katex": false + }, + "rules": { + "comma-dangle": [2, "never"], + "array-callback-return": 2, + "prefer-rest-params": 2, + "no-unmodified-loop-condition": 2, + "sort-imports": 0, + "no-new-symbol": 2, + "no-empty-function": 2, + "no-whitespace-before-property": 2, + "no-useless-constructor": 2, + "id-blacklist": 0, + "one-var-declaration-per-line": 0, + "no-extra-label": 2, + "template-curly-spacing": [2, "never"], + "no-self-assign": 2, + "newline-per-chained-call": 0, + "no-confusing-arrow": 2, + "no-case-declarations": 2, + "no-cond-assign": [2, "except-parens"], + "no-console": 2, + "no-constant-condition": 2, + "no-debugger": 2, + "no-dupe-args": 2, + "no-dupe-keys": 2, + "no-duplicate-case": 2, + "no-empty": 2, + "no-empty-pattern": 2, + "no-ex-assign": 2, + "no-extra-semi": 2, + "no-fallthrough": 2, + "no-func-assign": 2, + "no-inner-declarations": 0, + "no-invalid-regexp": 2, + "no-irregular-whitespace": 2, + "no-unexpected-multiline": 2, + "no-unreachable": 2, + "no-magic-numbers": [1, { "ignore": [-1, 0, 1, 2], "enforceConst": true, "detectObjects": true } ], + "valid-typeof": 2, + + "block-scoped-var": 2, + "complexity": [0, 8], + "consistent-return": 2, + "curly": [2, "all"], + "dot-location": [2, "object"], + "dot-notation": 2, + "eqeqeq": [2, "smart"], + "global-require": 2, + "guard-for-in": 2, + "no-alert": 2, + "no-array-constructor": 2, + "no-caller": 2, + "no-div-regex": 2, + "no-else-return": 2, + "no-eval": 2, + "no-extend-native": 2, + "no-extra-bind": 2, + "no-floating-decimal": 2, + "no-implied-eval": 2, + "no-implicit-globals": 0, + "no-iterator": 2, + "no-labels": 2, + "no-lone-blocks": 2, + "no-loop-func": 2, + "no-multi-spaces": [2, { "exceptions": { "Property": false } }], + "no-multi-str": 0, + "no-native-reassign": 2, + "no-new": 2, + "no-new-func": 2, + "no-new-object": 2, + "no-new-wrappers": 2, + "no-octal-escape": 2, + "no-param-reassign": 2, + "no-process-env": 2, + "no-process-exit": 2, + "no-proto": 2, + "no-redeclare": 2, + "no-return-assign": [2, "always"], + "no-script-url": 2, + "no-self-compare": 2, + "no-sequences": 2, + "no-throw-literal": 2, + "no-undef-init": 2, + "no-unused-expressions": 2, + "no-useless-concat": 1, + "no-void": 2, + "no-warning-comments": 1, + "no-with": 2, + "radix": 2, + "vars-on-top": 0, + "wrap-iife": [2, "outside"], + "yoda": [2, "never", {"exceptRange": false, "onlyEquality": false}], + + "no-undefined": 2, + "no-shadow": [2, {"hoist": "functions"}], + "no-shadow-restricted-names": 2, + "no-unused-vars": [2, {"vars": "all", "args": "after-used"}], + "no-use-before-define": [2, "nofunc"], + + // Style + "array-bracket-spacing": [2, "never"], + "brace-style": [2, "1tbs", { "allowSingleLine": false }], + "camelcase": [2, {"properties": "never"}], + "comma-spacing": [2, {"before": false, "after": true}], + "comma-style": [2, "last"], + "computed-property-spacing": [2, "never"], + "consistent-this": [2, "self"], + "func-names": 2, + "func-style": [2, "declaration"], + "indent": [2, 4, {"SwitchCase": 0}], + "jsx-quotes": [2, "prefer-single"], + "key-spacing": [2, {"beforeColon": false, "afterColon": true}], + "linebreak-style": 2, + "lines-around-comment": [2, { "beforeBlockComment": true, "beforeLineComment": true, "allowBlockStart": true, "allowBlockEnd": true }], + "new-cap": 2, + "new-parens": 2, + "no-lonely-if": 2, + "no-mixed-spaces-and-tabs": 2, + "no-multiple-empty-lines": [2, {"max": 1}], + "no-negated-condition": 2, + "no-nested-ternary": 2, + "no-spaced-func": 2, + "no-ternary": 0, + "no-trailing-spaces": [2, { "skipBlankLines": false }], + "no-underscore-dangle": 2, + "no-unneeded-ternary": [2, {"defaultAssignment": false}], + "object-curly-spacing": [2, "never"], + "one-var": [2, "never"], + "operator-linebreak": [2, "after"], + "padded-blocks": [2, "never"], + "quote-props": [2, "as-needed"], + "quotes": [2, "single", "avoid-escape"], + "semi": [2, "always"], + "semi-spacing": [2, {"before": false, "after": true}], + "keyword-spacing": [2, {"before": true, "after": true, "overrides": {}}], + "space-before-blocks": [2, "always"], + "space-before-function-paren": [2, "never"], + "space-in-parens": [2, "never"], + "space-infix-ops": 2, + "space-unary-ops": [2, { "words": true, "nonwords": false }], + "wrap-regex": 2, + + // ES6 stuff + "arrow-parens": [2, "always"], + "arrow-body-style": 0, + "arrow-spacing": [2, { "before": true, "after": true }], + "constructor-super": 2, + "generator-star-spacing": [2, {"before": false, "after": true}], + "no-class-assign": 2, + "no-const-assign": 2, + "no-dupe-class-members": 2, + "no-this-before-super": 2, + "no-var": 0, + "object-shorthand": [1, "always"], + "prefer-arrow-callback": 1, + "prefer-const": 1, + "prefer-spread": 2, + "prefer-reflect": 1, + "prefer-template": 0, + "require-yield": 2, + + // React Specific + "react/display-name": [2, { "ignoreTranspilerName": false }], + "react/no-deprecated": 2, + "react/no-is-mounted": 2, + "react/no-string-refs": 1, + "react/jsx-pascal-case": 2, + "react/jsx-indent": [1, 4], + "react/jsx-equals-spacing": [2, "never"], + "react/jsx-handler-names": 0, + "react/jsx-boolean-value": [2, "always"], + "react/jsx-closing-bracket-location": [2, { "location": "tag-aligned" }], + "react/jsx-curly-spacing": [2, "never"], + "react/jsx-indent-props": [2, 4], + "react/jsx-key": 2, + "react/jsx-max-props-per-line": [2, { "maximum": 1 }], + "react/jsx-no-bind": 1, + "react/jsx-space-before-closing": [2, "never"], + "react/jsx-no-duplicate-props": [2, { "ignoreCase": false }], + "react/jsx-no-literals": 1, + "react/jsx-no-undef": 2, + "react/jsx-uses-react": 2, + "react/jsx-uses-vars": 2, + "react/no-danger": 0, + "react/no-did-mount-set-state": 2, + "react/no-did-update-set-state": 2, + "react/no-direct-mutation-state": 2, + "react/no-multi-comp": [2, { "ignoreStateless": true }], + "react/no-set-state": 0, + "react/no-unknown-property": 2, + "react/prefer-es6-class": 2, + "react/prop-types": 2, + "react/self-closing-comp": 2, + "react/sort-comp": 0, + "react/wrap-multilines": 2 + } +} diff --git a/web/react/components/access_history_modal.jsx b/web/react/components/access_history_modal.jsx index af4d3fb0f..cd1db32ec 100644 --- a/web/react/components/access_history_modal.jsx +++ b/web/react/components/access_history_modal.jsx @@ -68,7 +68,7 @@ class AccessHistoryModal extends React.Component { render() { var content; if (this.state.audits.loading) { - content = (<LoadingScreen />); + content = (<LoadingScreen/>); } else { content = ( <AuditTable diff --git a/web/react/components/activity_log_modal.jsx b/web/react/components/activity_log_modal.jsx index f8a2af571..1a0c9c6d5 100644 --- a/web/react/components/activity_log_modal.jsx +++ b/web/react/components/activity_log_modal.jsx @@ -199,7 +199,7 @@ export default class ActivityLogModal extends React.Component { className='activity-log__table' > <div className='activity-log__report'> - <div className='report__platform'><i className={devicePicture} />{devicePlatform}</div> + <div className='report__platform'><i className={devicePicture}/>{devicePlatform}</div> <div className='report__info'> <div> <FormattedMessage @@ -231,7 +231,7 @@ export default class ActivityLogModal extends React.Component { let content; if (this.state.sessions.loading) { - content = <LoadingScreen />; + content = <LoadingScreen/>; } else { content = <form role='form'>{activityList}</form>; } diff --git a/web/react/components/admin_console/admin_controller.jsx b/web/react/components/admin_console/admin_controller.jsx index 695e2083a..de0b085bc 100644 --- a/web/react/components/admin_console/admin_controller.jsx +++ b/web/react/components/admin_console/admin_controller.jsx @@ -130,47 +130,47 @@ export default class AdminController extends React.Component { } render() { - var tab = <LoadingScreen />; + var tab = <LoadingScreen/>; if (this.state.config != null) { if (this.state.selected === 'email_settings') { - tab = <EmailSettingsTab config={this.state.config} />; + tab = <EmailSettingsTab config={this.state.config}/>; } else if (this.state.selected === 'log_settings') { - tab = <LogSettingsTab config={this.state.config} />; + tab = <LogSettingsTab config={this.state.config}/>; } else if (this.state.selected === 'logs') { - tab = <LogsTab />; + tab = <LogsTab/>; } else if (this.state.selected === 'audits') { - tab = <AuditsTab />; + tab = <AuditsTab/>; } else if (this.state.selected === 'image_settings') { - tab = <FileSettingsTab config={this.state.config} />; + tab = <FileSettingsTab config={this.state.config}/>; } else if (this.state.selected === 'privacy_settings') { - tab = <PrivacySettingsTab config={this.state.config} />; + tab = <PrivacySettingsTab config={this.state.config}/>; } else if (this.state.selected === 'rate_settings') { - tab = <RateSettingsTab config={this.state.config} />; + tab = <RateSettingsTab config={this.state.config}/>; } else if (this.state.selected === 'gitlab_settings') { - tab = <GitLabSettingsTab config={this.state.config} />; + tab = <GitLabSettingsTab config={this.state.config}/>; } else if (this.state.selected === 'sql_settings') { - tab = <SqlSettingsTab config={this.state.config} />; + tab = <SqlSettingsTab config={this.state.config}/>; } else if (this.state.selected === 'team_settings') { - tab = <TeamSettingsTab config={this.state.config} />; + tab = <TeamSettingsTab config={this.state.config}/>; } else if (this.state.selected === 'service_settings') { - tab = <ServiceSettingsTab config={this.state.config} />; + tab = <ServiceSettingsTab config={this.state.config}/>; } else if (this.state.selected === 'legal_and_support_settings') { - tab = <LegalAndSupportSettingsTab config={this.state.config} />; + tab = <LegalAndSupportSettingsTab config={this.state.config}/>; } else if (this.state.selected === 'ldap_settings') { - tab = <LdapSettingsTab config={this.state.config} />; + tab = <LdapSettingsTab config={this.state.config}/>; } else if (this.state.selected === 'license') { - tab = <LicenseSettingsTab config={this.state.config} />; + tab = <LicenseSettingsTab config={this.state.config}/>; } else if (this.state.selected === 'team_users') { if (this.state.teams) { - tab = <TeamUsersTab team={this.state.teams[this.state.selectedTeam]} />; + tab = <TeamUsersTab team={this.state.teams[this.state.selectedTeam]}/>; } } else if (this.state.selected === 'team_analytics') { if (this.state.teams) { - tab = <TeamAnalyticsTab team={this.state.teams[this.state.selectedTeam]} />; + tab = <TeamAnalyticsTab team={this.state.teams[this.state.selectedTeam]}/>; } } else if (this.state.selected === 'system_analytics') { - tab = <SystemAnalyticsTab />; + tab = <SystemAnalyticsTab/>; } } diff --git a/web/react/components/admin_console/admin_sidebar.jsx b/web/react/components/admin_console/admin_sidebar.jsx index 795b19eec..6621e5743 100644 --- a/web/react/components/admin_console/admin_sidebar.jsx +++ b/web/react/components/admin_console/admin_sidebar.jsx @@ -236,7 +236,7 @@ export default class AdminSidebar extends React.Component { return ( <div className='sidebar--left sidebar--collapsable'> <div> - <AdminSidebarHeader /> + <AdminSidebarHeader/> <div className='nav-pills__container'> <ul className='nav nav-pills nav-stacked'> <li> diff --git a/web/react/components/admin_console/admin_sidebar_header.jsx b/web/react/components/admin_console/admin_sidebar_header.jsx index db499265e..8c9f74934 100644 --- a/web/react/components/admin_console/admin_sidebar_header.jsx +++ b/web/react/components/admin_console/admin_sidebar_header.jsx @@ -61,7 +61,7 @@ export default class SidebarHeader extends React.Component { </div> </div> </a> - <AdminNavbarDropdown ref='dropdown' /> + <AdminNavbarDropdown ref='dropdown'/> </div> ); } diff --git a/web/react/components/admin_console/audits.jsx b/web/react/components/admin_console/audits.jsx index 173e63b45..c519e0a23 100644 --- a/web/react/components/admin_console/audits.jsx +++ b/web/react/components/admin_console/audits.jsx @@ -54,7 +54,7 @@ export default class Audits extends React.Component { } if (this.state.audits === null) { - content = <LoadingScreen />; + content = <LoadingScreen/>; } else { content = ( <div style={{margin: '10px'}}> diff --git a/web/react/components/admin_console/license_settings.jsx b/web/react/components/admin_console/license_settings.jsx index 3332f37ef..fdbe912ef 100644 --- a/web/react/components/admin_console/license_settings.jsx +++ b/web/react/components/admin_console/license_settings.jsx @@ -203,8 +203,7 @@ class LicenseSettings extends React.Component { <p className='help-text'> <FormattedHTMLMessage id='admin.license.uploadDesc' - defaultMessage='Upload a license key for Mattermost Enterprise Edition to upgrade this server. <a href="http://mattermost.com" target="_blank">Visit us online</a> - to learn more about the benefits of Enterprise Edition or to purchase a key.' + defaultMessage='Upload a license key for Mattermost Enterprise Edition to upgrade this server. <a href="http://mattermost.com" target="_blank">Visit us online</a> to learn more about the benefits of Enterprise Edition or to purchase a key.' /> </p> </div> diff --git a/web/react/components/admin_console/logs.jsx b/web/react/components/admin_console/logs.jsx index 71a4a5d8c..8457999f5 100644 --- a/web/react/components/admin_console/logs.jsx +++ b/web/react/components/admin_console/logs.jsx @@ -47,7 +47,7 @@ export default class Logs extends React.Component { var content = null; if (this.state.logs === null) { - content = <LoadingScreen />; + content = <LoadingScreen/>; } else { content = []; @@ -61,7 +61,7 @@ export default class Logs extends React.Component { style.color = 'red'; } - content.push(<br key={'br_' + i} />); + content.push(<br key={'br_' + i}/>); content.push( <span key={'log_' + i} diff --git a/web/react/components/admin_console/service_settings.jsx b/web/react/components/admin_console/service_settings.jsx index f232d4633..047c7eb8d 100644 --- a/web/react/components/admin_console/service_settings.jsx +++ b/web/react/components/admin_console/service_settings.jsx @@ -287,9 +287,7 @@ class ServiceSettings extends React.Component { <p className='help-text'> <FormattedHTMLMessage id='admin.service.googleDescription' - defaultMessage='Set this key to enable embedding of YouTube video previews based on hyperlinks appearing in messages or comments. Instructions to obtain a key available at - <a href="https://www.youtube.com/watch?v=Im69kzhpR3I" target="_blank">https://www.youtube.com/watch?v=Im69kzhpR3I</a>. - Leaving the field blank disables the automatic generation of YouTube video previews from links.' + defaultMessage='Set this key to enable embedding of YouTube video previews based on hyperlinks appearing in messages or comments. Instructions to obtain a key available at <a href="https://www.youtube.com/watch?v=Im69kzhpR3I" target="_blank">https://www.youtube.com/watch?v=Im69kzhpR3I</a>. Leaving the field blank disables the automatic generation of YouTube video previews from links.' /> </p> </div> diff --git a/web/react/components/admin_console/statistic_count.jsx b/web/react/components/admin_console/statistic_count.jsx index 57af0ed1b..118a0ad31 100644 --- a/web/react/components/admin_console/statistic_count.jsx +++ b/web/react/components/admin_console/statistic_count.jsx @@ -4,10 +4,6 @@ import {FormattedMessage} from 'mm-intl'; export default class StatisticCount extends React.Component { - constructor(props) { - super(props); - } - render() { let loading = ( <FormattedMessage diff --git a/web/react/components/admin_console/team_users.jsx b/web/react/components/admin_console/team_users.jsx index 1177c9c56..256576f9b 100644 --- a/web/react/components/admin_console/team_users.jsx +++ b/web/react/components/admin_console/team_users.jsx @@ -112,9 +112,6 @@ export default class UserList extends React.Component { this.getTeamProfiles(newProps.team.id); } - componentWillUnmount() { - } - render() { var serverError = ''; if (this.state.serverError) { @@ -134,7 +131,7 @@ export default class UserList extends React.Component { /> </h3> {serverError} - <LoadingScreen /> + <LoadingScreen/> </div> ); } diff --git a/web/react/components/audit_table.jsx b/web/react/components/audit_table.jsx index 31d04f19b..47eee6d3f 100644 --- a/web/react/components/audit_table.jsx +++ b/web/react/components/audit_table.jsx @@ -207,9 +207,6 @@ const holders = defineMessages({ }); class AuditTable extends React.Component { - constructor(props) { - super(props); - } render() { var accessList = []; diff --git a/web/react/components/authorize.jsx b/web/react/components/authorize.jsx index 4a4985268..35ad7ac10 100644 --- a/web/react/components/authorize.jsx +++ b/web/react/components/authorize.jsx @@ -27,7 +27,9 @@ export default class Authorize extends React.Component { window.location.replace(data.redirect); } }, - () => {} + () => { + //Do nothing on error + } ); } handleDeny() { diff --git a/web/react/components/center_panel.jsx b/web/react/components/center_panel.jsx index 7d2be04d6..6cb749075 100644 --- a/web/react/components/center_panel.jsx +++ b/web/react/components/center_panel.jsx @@ -55,10 +55,10 @@ export default class CenterPanel extends React.Component { let postsContainer; let createPost; if (this.state.showTutorialScreens) { - postsContainer = <TutorialIntroScreens />; + postsContainer = <TutorialIntroScreens/>; createPost = null; } else if (this.state.showPostFocus) { - postsContainer = <PostFocusView />; + postsContainer = <PostFocusView/>; handleClick = function clickHandler(e) { e.preventDefault(); @@ -80,13 +80,13 @@ export default class CenterPanel extends React.Component { </div> ); } else { - postsContainer = <PostsViewContainer />; + postsContainer = <PostsViewContainer/>; createPost = ( <div className='post-create__container' id='post-create' > - <CreatePost /> + <CreatePost/> </div> ); } @@ -108,7 +108,7 @@ export default class CenterPanel extends React.Component { className='app__content' > <div id='channel-header'> - <ChannelHeader /> + <ChannelHeader/> </div> {postsContainer} {createPost} diff --git a/web/react/components/channel_header.jsx b/web/react/components/channel_header.jsx index a827cbcc6..079a9451e 100644 --- a/web/react/components/channel_header.jsx +++ b/web/react/components/channel_header.jsx @@ -11,6 +11,7 @@ import ChannelInviteModal from './channel_invite_modal.jsx'; import ChannelMembersModal from './channel_members_modal.jsx'; import ChannelNotificationsModal from './channel_notifications_modal.jsx'; import DeleteChannelModal from './delete_channel_modal.jsx'; +import RenameChannelModal from './rename_channel_modal.jsx'; import ToggleModalButton from './toggle_modal_button.jsx'; import ChannelStore from '../stores/channel_store.jsx'; @@ -39,10 +40,13 @@ export default class ChannelHeader extends React.Component { this.onListenerChange = this.onListenerChange.bind(this); this.handleLeave = this.handleLeave.bind(this); this.searchMentions = this.searchMentions.bind(this); + this.showRenameChannelModal = this.showRenameChannelModal.bind(this); + this.hideRenameChannelModal = this.hideRenameChannelModal.bind(this); const state = this.getStateFromStores(); state.showEditChannelPurposeModal = false; state.showMembersModal = false; + state.showRenameChannelModal = false; this.state = state; } getStateFromStores() { @@ -120,6 +124,18 @@ export default class ChannelHeader extends React.Component { is_mention_search: true }); } + showRenameChannelModal(e) { + e.preventDefault(); + + this.setState({ + showRenameChannelModal: true + }); + } + hideRenameChannelModal() { + this.setState({ + showRenameChannelModal: false + }); + } render() { if (this.state.channel === null) { return null; @@ -326,11 +342,7 @@ export default class ChannelHeader extends React.Component { <a role='menuitem' href='#' - data-toggle='modal' - data-target='#rename_channel' - data-display={channel.display_name} - data-name={channel.name} - data-channelid={channel.id} + onClick={this.showRenameChannelModal} > <FormattedMessage id='channel_header.rename' @@ -408,7 +420,7 @@ export default class ChannelHeader extends React.Component { aria-expanded='true' > <strong className='heading'>{channelTitle} </strong> - <span className='glyphicon glyphicon-chevron-down header-dropdown__icon' /> + <span className='glyphicon glyphicon-chevron-down header-dropdown__icon'/> </a> <ul className='dropdown-menu' @@ -439,7 +451,7 @@ export default class ChannelHeader extends React.Component { channelId={channel.id} /> </th> - <th className='search-bar__container'><NavbarSearchBox /></th> + <th className='search-bar__container'><NavbarSearchBox/></th> <th> <div className='dropdown channel-header__links'> <OverlayTrigger @@ -470,6 +482,11 @@ export default class ChannelHeader extends React.Component { onModalDismissed={() => this.setState({showMembersModal: false})} channel={channel} /> + <RenameChannelModal + show={this.state.showRenameChannelModal} + onHide={this.hideRenameChannelModal} + channel={channel} + /> </div> ); } diff --git a/web/react/components/channel_invite_modal.jsx b/web/react/components/channel_invite_modal.jsx index 7dc2c0a11..c9fe871d0 100644 --- a/web/react/components/channel_invite_modal.jsx +++ b/web/react/components/channel_invite_modal.jsx @@ -138,7 +138,7 @@ export default class ChannelInviteModal extends React.Component { var content; if (this.state.loading) { - content = (<LoadingScreen />); + content = (<LoadingScreen/>); } else { content = ( <MemberList diff --git a/web/react/components/channel_members_modal.jsx b/web/react/components/channel_members_modal.jsx index f3cbef719..fd452f206 100644 --- a/web/react/components/channel_members_modal.jsx +++ b/web/react/components/channel_members_modal.jsx @@ -172,7 +172,7 @@ export default class ChannelMembersModal extends React.Component { let content; if (this.state.loading) { - content = (<LoadingScreen />); + content = (<LoadingScreen/>); } else { content = ( <div className='team-member-list'> diff --git a/web/react/components/channel_notifications_modal.jsx b/web/react/components/channel_notifications_modal.jsx index 59ef8966e..7048434f8 100644 --- a/web/react/components/channel_notifications_modal.jsx +++ b/web/react/components/channel_notifications_modal.jsx @@ -153,7 +153,7 @@ export default class ChannelNotificationsModal extends React.Component { /> <FormattedMessage id='channel_notifications.globalDefault' - defaultMessage='Global default ({notifyLevel}' + defaultMessage='Global default ({notifyLevel})' values={{ notifyLevel: (globalNotifyLevelName) }} @@ -168,7 +168,7 @@ export default class ChannelNotificationsModal extends React.Component { checked={notifyActive[1]} onChange={this.handleUpdateNotifyLevel.bind(this, 'all')} /> - <FormattedMessage id='channel_notifications.allActivity' /> + <FormattedMessage id='channel_notifications.allActivity'/> </label> <br/> </div> @@ -179,7 +179,7 @@ export default class ChannelNotificationsModal extends React.Component { checked={notifyActive[2]} onChange={this.handleUpdateNotifyLevel.bind(this, 'mention')} /> - <FormattedMessage id='channel_notifications.onlyMentions' /> + <FormattedMessage id='channel_notifications.onlyMentions'/> </label> <br/> </div> @@ -190,7 +190,7 @@ export default class ChannelNotificationsModal extends React.Component { checked={notifyActive[3]} onChange={this.handleUpdateNotifyLevel.bind(this, 'none')} /> - <FormattedMessage id='channel_notifications.never' /> + <FormattedMessage id='channel_notifications.never'/> </label> </div> </div> @@ -234,11 +234,11 @@ export default class ChannelNotificationsModal extends React.Component { /> ); } else if (this.state.notifyLevel === 'mention') { - describe = (<FormattedMessage id='channel_notifications.onlyMentions' />); + describe = (<FormattedMessage id='channel_notifications.onlyMentions'/>); } else if (this.state.notifyLevel === 'all') { - describe = (<FormattedMessage id='channel_notifications.allActivity' />); + describe = (<FormattedMessage id='channel_notifications.allActivity'/>); } else { - describe = (<FormattedMessage id='channel_notifications.never' />); + describe = (<FormattedMessage id='channel_notifications.never'/>); } handleUpdateSection = function updateSection(e) { @@ -311,7 +311,7 @@ export default class ChannelNotificationsModal extends React.Component { defaultMessage='For all unread messages' /> </label> - <br /> + <br/> </div> <div className='radio'> <label> @@ -320,9 +320,9 @@ export default class ChannelNotificationsModal extends React.Component { checked={this.state.markUnreadLevel === 'mention'} onChange={this.handleUpdateMarkUnreadLevel.bind(this, 'mention')} /> - <FormattedMessage id='channel_notifications.onlyMentions' /> + <FormattedMessage id='channel_notifications.onlyMentions'/> </label> - <br /> + <br/> </div> </div> )]; @@ -363,7 +363,7 @@ export default class ChannelNotificationsModal extends React.Component { /> ); } else { - describe = (<FormattedMessage id='channel_notifications.onlyMentions' />); + describe = (<FormattedMessage id='channel_notifications.onlyMentions'/>); } const handleUpdateSection = function handleUpdateSection(e) { diff --git a/web/react/components/channel_view.jsx b/web/react/components/channel_view.jsx index 7cbb638a0..9c4131292 100644 --- a/web/react/components/channel_view.jsx +++ b/web/react/components/channel_view.jsx @@ -7,9 +7,6 @@ import SidebarRight from '../components/sidebar_right.jsx'; import SidebarRightMenu from '../components/sidebar_right_menu.jsx'; export default class ChannelView extends React.Component { - constructor(props) { - super(props); - } render() { return ( <div className='container-fluid'> @@ -31,7 +28,7 @@ export default class ChannelView extends React.Component { > <Sidebar/> </div> - <CenterPanel /> + <CenterPanel/> </div> ); } diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx index 48b6594a1..9d7a19554 100644 --- a/web/react/components/create_post.jsx +++ b/web/react/components/create_post.jsx @@ -477,7 +477,7 @@ class CreatePost extends React.Component { className='send-button theme' onClick={this.handleSubmit} > - <i className='fa fa-paper-plane' /> + <i className='fa fa-paper-plane'/> </a> {tutorialTip} </div> diff --git a/web/react/components/delete_post_modal.jsx b/web/react/components/delete_post_modal.jsx index 95b2e58a8..773d0b420 100644 --- a/web/react/components/delete_post_modal.jsx +++ b/web/react/components/delete_post_modal.jsx @@ -178,8 +178,8 @@ export default class DeletePostModal extends React.Component { term: (postTerm) }} /> - <br /> - <br /> + <br/> + <br/> {commentWarning} {error} </Modal.Body> diff --git a/web/react/components/edit_post_modal.jsx b/web/react/components/edit_post_modal.jsx index e54b7d9b8..380ca7bde 100644 --- a/web/react/components/edit_post_modal.jsx +++ b/web/react/components/edit_post_modal.jsx @@ -135,9 +135,9 @@ class EditPostModal extends React.Component { PreferenceStore.removeChangeListener(this.onPreferenceChange); } render() { - var error = (<div className='form-group'><br /></div>); + var error = (<div className='form-group'><br/></div>); if (this.state.error) { - error = (<div className='form-group has-error'><br /><label className='control-label'>{this.state.error}</label></div>); + error = (<div className='form-group has-error'><br/><label className='control-label'>{this.state.error}</label></div>); } return ( diff --git a/web/react/components/email_verify.jsx b/web/react/components/email_verify.jsx index ef1a62130..702a20eba 100644 --- a/web/react/components/email_verify.jsx +++ b/web/react/components/email_verify.jsx @@ -70,7 +70,7 @@ export default class EmailVerify extends React.Component { ); if (this.props.resendSuccess) { resendConfirm = ( - <div><br /><p className='alert alert-success'><i className='fa fa-check'></i> + <div><br/><p className='alert alert-success'><i className='fa fa-check'></i> <FormattedMessage id='email_verify.sent' defaultMessage=' Verification email sent.' diff --git a/web/react/components/file_attachment.jsx b/web/react/components/file_attachment.jsx index 776394828..810f90b13 100644 --- a/web/react/components/file_attachment.jsx +++ b/web/react/components/file_attachment.jsx @@ -245,7 +245,9 @@ class FileAttachment extends React.Component { this.setState({fileSize: parseInt(data.size, 10), mime: data.mime}); } }.bind(this), - function error() {} + function error() { + // Do nothing + } ); } else { fileSizeString = utils.fileSizeToString(this.state.fileSize); @@ -312,4 +314,4 @@ FileAttachment.propTypes = { handleImageClick: React.PropTypes.func }; -export default injectIntl(FileAttachment);
\ No newline at end of file +export default injectIntl(FileAttachment); diff --git a/web/react/components/file_info_preview.jsx b/web/react/components/file_info_preview.jsx index 1dac140c9..30c3fc97f 100644 --- a/web/react/components/file_info_preview.jsx +++ b/web/react/components/file_info_preview.jsx @@ -37,7 +37,7 @@ export default function FileInfoPreview({filename, fileUrl, fileInfo, formatMess href={fileUrl} target='_blank' > - <span className='file-details__preview-helper' /> + <span className='file-details__preview-helper'/> <img src={Utils.getPreviewImagePath(filename)}/> </a> <div className='file-details'> @@ -47,3 +47,10 @@ export default function FileInfoPreview({filename, fileUrl, fileInfo, formatMess </div> ); } + +FileInfoPreview.propTypes = { + filename: React.PropTypes.string.isRequired, + fileUrl: React.PropTypes.string.isRequired, + fileInfo: React.PropTypes.object.isRequired, + formatMessage: React.PropTypes.func.isRequired +}; diff --git a/web/react/components/file_upload.jsx b/web/react/components/file_upload.jsx index 0454fe510..cb8ede51b 100644 --- a/web/react/components/file_upload.jsx +++ b/web/react/components/file_upload.jsx @@ -305,7 +305,7 @@ class FileUpload extends React.Component { className='btn btn-file' > <span> - <i className='glyphicon glyphicon-paperclip' /> + <i className='glyphicon glyphicon-paperclip'/> </span> <input ref='fileInput' diff --git a/web/react/components/get_link_modal.jsx b/web/react/components/get_link_modal.jsx index de3387a35..6a5c3b588 100644 --- a/web/react/components/get_link_modal.jsx +++ b/web/react/components/get_link_modal.jsx @@ -48,8 +48,8 @@ export default class GetLinkModal extends React.Component { helpText = ( <p> {this.props.helpText} - <br /> - <br /> + <br/> + <br/> </p> ); } diff --git a/web/react/components/invite_member_modal.jsx b/web/react/components/invite_member_modal.jsx index f2a0a7565..0c0330c40 100644 --- a/web/react/components/invite_member_modal.jsx +++ b/web/react/components/invite_member_modal.jsx @@ -376,7 +376,7 @@ class InviteMemberModal extends React.Component { ); if (this.state.isSendingEmails) { sendButtonLabel = ( - <span><i className='fa fa-spinner fa-spin' /> + <span><i className='fa fa-spinner fa-spin'/> <FormattedMessage id='invite_member.sending' defaultMessage=' Sending' diff --git a/web/react/components/login.jsx b/web/react/components/login.jsx index 0123a0f3c..380790b8f 100644 --- a/web/react/components/login.jsx +++ b/web/react/components/login.jsx @@ -28,7 +28,7 @@ export default class Login extends React.Component { key='gitlab' href={'/' + teamName + '/login/gitlab'} > - <span className='icon' /> + <span className='icon'/> <span> <FormattedMessage id='login.gitlab' @@ -46,7 +46,7 @@ export default class Login extends React.Component { key='google' href={'/' + teamName + '/login/google'} > - <span className='icon' /> + <span className='icon'/> <span> <FormattedMessage id='login.google' @@ -80,7 +80,7 @@ export default class Login extends React.Component { if (msg != null) { extraBox = ( <div className='alert alert-success'> - <i className='fa fa-check' /> + <i className='fa fa-check'/> {msg} </div> ); diff --git a/web/react/components/member_list.jsx b/web/react/components/member_list.jsx index 8c6dc4209..e6737087b 100644 --- a/web/react/components/member_list.jsx +++ b/web/react/components/member_list.jsx @@ -4,10 +4,6 @@ import MemberListItem from './member_list_item.jsx'; export default class MemberList extends React.Component { - constructor(props) { - super(props); - } - render() { var members = []; diff --git a/web/react/components/member_list_item.jsx b/web/react/components/member_list_item.jsx index 41ea58eeb..88b98738d 100644 --- a/web/react/components/member_list_item.jsx +++ b/web/react/components/member_list_item.jsx @@ -112,7 +112,7 @@ export default class MemberListItem extends React.Component { </div> ); } else { - invite = (<div className='member-role text-capitalize'><span className='fa fa-pencil hidden'></span>{member.roles || <FormattedMessage id='member_item.member' />}</div>); + invite = (<div className='member-role text-capitalize'><span className='fa fa-pencil hidden'></span>{member.roles || <FormattedMessage id='member_item.member'/>}</div>); } return ( diff --git a/web/react/components/more_channels.jsx b/web/react/components/more_channels.jsx index d800f93d8..db61e5f49 100644 --- a/web/react/components/more_channels.jsx +++ b/web/react/components/more_channels.jsx @@ -82,7 +82,7 @@ export default class MoreChannels extends React.Component { if (this.state.channels != null) { var channels = this.state.channels; if (channels.loading) { - moreChannels = <LoadingScreen />; + moreChannels = <LoadingScreen/>; } else if (channels.length) { moreChannels = ( <table className='more-table table'> diff --git a/web/react/components/navbar.jsx b/web/react/components/navbar.jsx index 835298635..85a6de6c8 100644 --- a/web/react/components/navbar.jsx +++ b/web/react/components/navbar.jsx @@ -5,11 +5,11 @@ import EditChannelHeaderModal from './edit_channel_header_modal.jsx'; import EditChannelPurposeModal from './edit_channel_purpose_modal.jsx'; import MessageWrapper from './message_wrapper.jsx'; import NotifyCounts from './notify_counts.jsx'; -import ChannelMembersModal from './channel_members_modal.jsx'; import ChannelInfoModal from './channel_info_modal.jsx'; import ChannelInviteModal from './channel_invite_modal.jsx'; import ChannelNotificationsModal from './channel_notifications_modal.jsx'; import DeleteChannelModal from './delete_channel_modal.jsx'; +import RenameChannelModal from './rename_channel_modal.jsx'; import ToggleModalButton from './toggle_modal_button.jsx'; import UserStore from '../stores/user_store.jsx'; @@ -39,6 +39,8 @@ export default class Navbar extends React.Component { this.showSearch = this.showSearch.bind(this); this.showEditChannelHeaderModal = this.showEditChannelHeaderModal.bind(this); + this.showRenameChannelModal = this.showRenameChannelModal.bind(this); + this.hideRenameChannelModal = this.hideRenameChannelModal.bind(this); this.createCollapseButtons = this.createCollapseButtons.bind(this); this.createDropdown = this.createDropdown.bind(this); @@ -47,6 +49,7 @@ export default class Navbar extends React.Component { state.showEditChannelPurposeModal = false; state.showEditChannelHeaderModal = false; state.showMembersModal = false; + state.showRenameChannelModal = false; this.state = state; } getStateFromStores() { @@ -128,6 +131,18 @@ export default class Navbar extends React.Component { showEditChannelHeaderModal: true }); } + showRenameChannelModal(e) { + e.preventDefault(); + + this.setState({ + showRenameChannelModal: true + }); + } + hideRenameChannelModal() { + this.setState({ + showRenameChannelModal: false + }); + } createDropdown(channel, channelTitle, isAdmin, isDirect, popoverContent) { if (channel) { var viewInfoOption = ( @@ -253,11 +268,7 @@ export default class Navbar extends React.Component { <a role='menuitem' href='#' - data-toggle='modal' - data-target='#rename_channel' - data-display={channel.display_name} - data-name={channel.name} - data-channelid={channel.id} + onClick={this.showRenameChannelModal} > <FormattedMessage id='navbar.rename' @@ -380,7 +391,7 @@ export default class Navbar extends React.Component { <span className='icon-bar'></span> <span className='icon-bar'></span> <span className='icon-bar'></span> - <NotifyCounts /> + <NotifyCounts/> </button> ); @@ -393,7 +404,7 @@ export default class Navbar extends React.Component { data-target='#sidebar-nav' onClick={this.toggleRightSidebar} > - <span dangerouslySetInnerHTML={{__html: Constants.MENU_ICON}} /> + <span dangerouslySetInnerHTML={{__html: Constants.MENU_ICON}}/> </button> ); } @@ -410,6 +421,7 @@ export default class Navbar extends React.Component { var editChannelHeaderModal = null; var editChannelPurposeModal = null; + let renameChannelModal = null; if (channel) { popoverContent = ( @@ -492,6 +504,14 @@ export default class Navbar extends React.Component { channel={channel} /> ); + + renameChannelModal = ( + <RenameChannelModal + show={this.state.showRenameChannelModal} + onHide={this.hideRenameChannelModal} + channel={channel} + /> + ); } var collapseButtons = this.createCollapseButtons(currentId); @@ -502,7 +522,7 @@ export default class Navbar extends React.Component { className='navbar-toggle pull-right' onClick={this.showSearch} > - <span className='glyphicon glyphicon-search icon--white' /> + <span className='glyphicon glyphicon-search icon--white'/> </button> ); @@ -524,11 +544,7 @@ export default class Navbar extends React.Component { </nav> {editChannelHeaderModal} {editChannelPurposeModal} - <ChannelMembersModal - show={this.state.showMembersModal} - onModalDismissed={() => this.setState({showMembersModal: false})} - channel={{channel}} - /> + {renameChannelModal} </div> ); } diff --git a/web/react/components/post_attachment_list.jsx b/web/react/components/post_attachment_list.jsx index 9c6700e2d..ae03e15d3 100644 --- a/web/react/components/post_attachment_list.jsx +++ b/web/react/components/post_attachment_list.jsx @@ -4,10 +4,6 @@ import PostAttachment from './post_attachment.jsx'; export default class PostAttachmentList extends React.Component { - constructor(props) { - super(props); - } - render() { let content = []; this.props.attachments.forEach((attachment, i) => { diff --git a/web/react/components/post_attachment_oembed.jsx b/web/react/components/post_attachment_oembed.jsx index 4b12ee95e..d76e5f02e 100644 --- a/web/react/components/post_attachment_oembed.jsx +++ b/web/react/components/post_attachment_oembed.jsx @@ -46,6 +46,7 @@ export default class PostAttachmentOEmbed extends React.Component { } }); } + return null; } render() { diff --git a/web/react/components/post_body_additional_content.jsx b/web/react/components/post_body_additional_content.jsx index 7e6f3f037..4871eea4f 100644 --- a/web/react/components/post_body_additional_content.jsx +++ b/web/react/components/post_body_additional_content.jsx @@ -52,7 +52,7 @@ export default class PostBodyAdditionalContent extends React.Component { render() { let content = []; - if (Boolean(this.props.post.type)) { + if (this.props.post.type) { const component = this.getComponent(); if (component) { diff --git a/web/react/components/post_header.jsx b/web/react/components/post_header.jsx index 037b48096..c52391daa 100644 --- a/web/react/components/post_header.jsx +++ b/web/react/components/post_header.jsx @@ -15,7 +15,7 @@ export default class PostHeader extends React.Component { render() { var post = this.props.post; - let userProfile = <UserProfile userId={post.user_id} />; + let userProfile = <UserProfile userId={post.user_id}/>; let botIndicator; if (post.props && post.props.from_webhook) { diff --git a/web/react/components/posts_view.jsx b/web/react/components/posts_view.jsx index 19ab7d5aa..15810d9cf 100644 --- a/web/react/components/posts_view.jsx +++ b/web/react/components/posts_view.jsx @@ -252,7 +252,7 @@ export default class PostsView extends React.Component { key={currentPostDay.toDateString()} className='date-separator' > - <hr className='separator__hr' /> + <hr className='separator__hr'/> <div className='separator__text'> <FormattedDate value={currentPostDay} @@ -455,7 +455,7 @@ export default class PostsView extends React.Component { href='#' onClick={this.loadMorePostsBottom} > - <FormattedMessage id='posts_view.loadMore' /> + <FormattedMessage id='posts_view.loadMore'/> </a> ); } else { @@ -528,11 +528,11 @@ PostsView.propTypes = { function FloatingTimestamp({isScrolling, post}) { // only show on mobile if ($(window).width() > 768) { - return <noscript />; + return <noscript/>; } if (!post) { - return <noscript />; + return <noscript/>; } const dateString = ( @@ -557,10 +557,15 @@ function FloatingTimestamp({isScrolling, post}) { ); } +FloatingTimestamp.propTypes = { + isScrolling: React.PropTypes.bool.isRequired, + post: React.PropTypes.object +}; + function ScrollToBottomArrows({isScrolling, atBottom, onClick}) { // only show on mobile if ($(window).width() > 768) { - return <noscript />; + return <noscript/>; } let className = 'post-list__arrows'; @@ -573,7 +578,13 @@ function ScrollToBottomArrows({isScrolling, atBottom, onClick}) { className={className} onClick={onClick} > - <span dangerouslySetInnerHTML={{__html: Constants.SCROLL_BOTTOM_ICON}} /> + <span dangerouslySetInnerHTML={{__html: Constants.SCROLL_BOTTOM_ICON}}/> </div> ); } + +ScrollToBottomArrows.propTypes = { + isScrolling: React.PropTypes.bool.isRequired, + atBottom: React.PropTypes.bool.isRequired, + onClick: React.PropTypes.func.isRequired +}; diff --git a/web/react/components/posts_view_container.jsx b/web/react/components/posts_view_container.jsx index 631bd1872..972342021 100644 --- a/web/react/components/posts_view_container.jsx +++ b/web/react/components/posts_view_container.jsx @@ -173,7 +173,9 @@ export default class PostsViewContainer extends React.Component { scrollPostId={this.state.scrollPost} postViewScrolled={this.handlePostsViewScroll} loadMorePostsTopClicked={this.loadMorePostsTop} - loadMorePostsBottomClicked={() => {}} + loadMorePostsBottomClicked={() => { + // Do Nothing + }} showMoreMessagesTop={!this.state.atTop[this.state.currentChannelIndex]} showMoreMessagesBottom={false} introText={channel ? createChannelIntroMessage(channel) : null} diff --git a/web/react/components/rename_channel_modal.jsx b/web/react/components/rename_channel_modal.jsx index c467c0d87..49ebccdbb 100644 --- a/web/react/components/rename_channel_modal.jsx +++ b/web/react/components/rename_channel_modal.jsx @@ -4,11 +4,12 @@ import * as Utils from '../utils/utils.jsx'; import * as Client from '../utils/client.jsx'; import * as AsyncClient from '../utils/async_client.jsx'; -import ChannelStore from '../stores/channel_store.jsx'; import Constants from '../utils/constants.jsx'; import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl'; +const Modal = ReactBootstrap.Modal; + const holders = defineMessages({ required: { id: 'rename_channel.required', @@ -44,33 +45,81 @@ export default class RenameChannelModal extends React.Component { constructor(props) { super(props); + this.handleShow = this.handleShow.bind(this); + this.handleHide = this.handleHide.bind(this); this.handleSubmit = this.handleSubmit.bind(this); + this.handleCancel = this.handleCancel.bind(this); + this.onNameChange = this.onNameChange.bind(this); this.onDisplayNameChange = this.onDisplayNameChange.bind(this); this.displayNameKeyUp = this.displayNameKeyUp.bind(this); - this.handleClose = this.handleClose.bind(this); - this.handleShow = this.handleShow.bind(this); - this.handleShown = this.handleShown.bind(this); - this.handleSubmit = this.handleSubmit.bind(this); this.state = { - displayName: '', - channelName: '', - channelId: '', + displayName: props.channel.display_name, + channelName: props.channel.name, serverError: '', nameError: '', displayNameError: '', invalid: false }; } - handleSubmit(e) { - e.preventDefault(); - if (this.state.channelId.length !== 26) { - return; + componentWillReceiveProps(nextProps) { + if (!Utils.areObjectsEqual(nextProps.channel, this.props.channel)) { + this.setState({ + displayName: nextProps.channel.display_name, + channelName: nextProps.channel.name + }); } + } + + shouldComponentUpdate(nextProps, nextState) { + if (!nextProps.show && !this.props.show) { + return false; + } + + if (!Utils.areObjectsEqual(nextState, this.state)) { + return true; + } + + if (!Utils.areObjectsEqual(nextProps, this.props)) { + return true; + } + + return false; + } + + componentDidUpdate(prevProps) { + if (!prevProps.show && this.props.show) { + this.handleShow(); + } + } + + handleShow() { + const textbox = ReactDOM.findDOMNode(this.refs.displayName); + textbox.focus(); + Utils.placeCaretAtEnd(textbox); + } + + handleHide(e) { + if (e) { + e.preventDefault(); + } + + this.props.onHide(); + + this.setState({ + serverError: '', + nameError: '', + displayNameError: '', + invalid: false + }); + } - const channel = ChannelStore.get(this.state.channelId); + handleSubmit(e) { + e.preventDefault(); + + const channel = Object.assign({}, this.props.channel); const oldName = channel.name; const oldDisplayName = channel.displayName; const state = {serverError: ''}; @@ -110,29 +159,40 @@ export default class RenameChannelModal extends React.Component { return; } - Client.updateChannel(channel, + Client.updateChannel( + channel, () => { - $(ReactDOM.findDOMNode(this.refs.modal)).modal('hide'); - AsyncClient.getChannel(channel.id); Utils.updateAddressBar(channel.name); - ReactDOM.findDOMNode(this.refs.displayName).value = ''; - ReactDOM.findDOMNode(this.refs.channelName).value = ''; + this.handleHide(); }, (err) => { - state.serverError = err.message; - state.invalid = true; - this.setState(state); + this.setState({ + serverError: err.message, + invalid: true + }); } ); } + + handleCancel(e) { + this.setState({ + displayName: this.props.channel.display_name, + channelName: this.props.channel.name + }); + + this.handleHide(e); + } + onNameChange() { this.setState({channelName: ReactDOM.findDOMNode(this.refs.channelName).value}); } + onDisplayNameChange() { this.setState({displayName: ReactDOM.findDOMNode(this.refs.displayName).value}); } + displayNameKeyUp() { if (this.state.channelName !== Constants.DEFAULT_CHANNEL) { const displayName = ReactDOM.findDOMNode(this.refs.displayName).value.trim(); @@ -141,32 +201,7 @@ export default class RenameChannelModal extends React.Component { this.setState({channelName: channelName}); } } - handleClose() { - this.setState({ - displayName: '', - channelName: '', - channelId: '', - serverError: '', - nameError: '', - displayNameError: '', - invalid: false - }); - } - handleShow(e) { - const button = $(e.relatedTarget); - this.setState({displayName: button.attr('data-display'), channelName: button.attr('data-name'), channelId: button.attr('data-channelid')}); - } - handleShown() { - $('#rename_channel #display_name').focus(); - } - componentDidMount() { - $(ReactDOM.findDOMNode(this.refs.modal)).on('show.bs.modal', this.handleShow); - $(ReactDOM.findDOMNode(this.refs.modal)).on('hidden.bs.modal', this.handleClose); - $(ReactDOM.findDOMNode(this.refs.modal)).on('shown.bs.modal', this.handleShown); - } - componentWillUnmount() { - $(ReactDOM.findDOMNode(this.refs.modal)).off('hidden.bs.modal', this.handleClose); - } + render() { let displayNameError = null; let displayNameClass = 'form-group'; @@ -199,107 +234,89 @@ export default class RenameChannelModal extends React.Component { } return ( - <div - className='modal fade' - ref='modal' - id='rename_channel' - tabIndex='-1' - role='dialog' - aria-hidden='true' + <Modal + show={this.props.show} + onHide={this.handleCancel} > - <div className='modal-dialog'> - <div className='modal-content'> - <div className='modal-header'> - <button - type='button' - className='close' - data-dismiss='modal' - > - <span aria-hidden='true'>{'×'}</span> - <span className='sr-only'> - <FormattedMessage - id='rename_channel.close' - defaultMessage='Close' - /> - </span> - </button> - <h4 className='modal-title'> - <FormattedMessage - id='rename_channel.title' - defaultMessage='Rename Channel' + <Modal.Header closeButton={true}> + <Modal.Title> + <FormattedMessage + id='rename_channel.title' + defaultMessage='Rename Channel' + /> + </Modal.Title> + </Modal.Header> + <form role='form'> + <Modal.Body> + <div className={displayNameClass}> + <label className='control-label'> + <FormattedMessage + id='rename_channel.displayName' + defaultMessage='Display Name' + /> + </label> + <input + onKeyUp={this.displayNameKeyUp} + onChange={this.onDisplayNameChange} + type='text' + ref='displayName' + id='display_name' + className='form-control' + placeholder={formatMessage(holders.displayNameHolder)} + value={this.state.displayName} + maxLength='64' + /> + {displayNameError} + </div> + <div className={nameClass}> + <label className='control-label'>{handleInputLabel}</label> + <input + onChange={this.onNameChange} + type='text' + className={handleInputClass} + ref='channelName' + placeholder={formatMessage(holders.handleHolder)} + value={this.state.channelName} + maxLength='64' + readOnly={readOnlyHandleInput} /> - </h4> + {nameError} </div> - <form role='form'> - <div className='modal-body'> - <div className={displayNameClass}> - <label className='control-label'> - <FormattedMessage - id='rename_channel.displayName' - defaultMessage='Display Name' - /> - </label> - <input - onKeyUp={this.displayNameKeyUp} - onChange={this.onDisplayNameChange} - type='text' - ref='displayName' - id='display_name' - className='form-control' - placeholder={formatMessage(holders.displayNameHolder)} - value={this.state.displayName} - maxLength='64' - /> - {displayNameError} - </div> - <div className={nameClass}> - <label className='control-label'>{handleInputLabel}</label> - <input - onChange={this.onNameChange} - type='text' - className={handleInputClass} - ref='channelName' - placeholder={formatMessage(holders.handleHolder)} - value={this.state.channelName} - maxLength='64' - readOnly={readOnlyHandleInput} - /> - {nameError} - </div> - {serverError} - </div> - <div className='modal-footer'> - <button - type='button' - className='btn btn-default' - data-dismiss='modal' - > - <FormattedMessage - id='rename_channel.cancel' - defaultMessage='Cancel' - /> - </button> - <button - onClick={this.handleSubmit} - type='submit' - className='btn btn-primary' - > - <FormattedMessage - id='rename_channel.save' - defaultMessage='Save' - /> - </button> - </div> - </form> - </div> - </div> - </div> + {serverError} + </Modal.Body> + <Modal.Footer> + <button + type='button' + className='btn btn-default' + onClick={this.handleCancel} + > + <FormattedMessage + id='rename_channel.cancel' + defaultMessage='Cancel' + /> + </button> + <button + onClick={this.handleSubmit} + type='submit' + className='btn btn-primary' + > + <FormattedMessage + id='rename_channel.save' + defaultMessage='Save' + /> + </button> + </Modal.Footer> + </form> + </Modal> ); } } RenameChannelModal.propTypes = { - intl: intlShape.isRequired + intl: intlShape.isRequired, + show: React.PropTypes.bool.isRequired, + onHide: React.PropTypes.func.isRequired, + channel: React.PropTypes.object.isRequired }; -export default injectIntl(RenameChannelModal);
\ No newline at end of file +export default injectIntl(RenameChannelModal); diff --git a/web/react/components/rhs_comment.jsx b/web/react/components/rhs_comment.jsx index 201a4c569..2ebca9b8d 100644 --- a/web/react/components/rhs_comment.jsx +++ b/web/react/components/rhs_comment.jsx @@ -246,7 +246,7 @@ class RhsComment extends React.Component { <div> <ul className='post__header'> <li className='col__name'> - <strong><UserProfile userId={post.user_id} /></strong> + <strong><UserProfile userId={post.user_id}/></strong> </li> <li className='col'> <time className='post__time'> diff --git a/web/react/components/rhs_root_post.jsx b/web/react/components/rhs_root_post.jsx index adf66da85..32946ef23 100644 --- a/web/react/components/rhs_root_post.jsx +++ b/web/react/components/rhs_root_post.jsx @@ -185,7 +185,7 @@ export default class RhsRootPost extends React.Component { ); } - let userProfile = <UserProfile userId={post.user_id} />; + let userProfile = <UserProfile userId={post.user_id}/>; let botIndicator; if (post.props && post.props.from_webhook) { diff --git a/web/react/components/rhs_thread.jsx b/web/react/components/rhs_thread.jsx index 945b09e37..667030b3a 100644 --- a/web/react/components/rhs_thread.jsx +++ b/web/react/components/rhs_thread.jsx @@ -196,12 +196,12 @@ export default class RhsThread extends React.Component { var currentId = UserStore.getCurrentId(); var searchForm; if (currentId != null) { - searchForm = <SearchBox />; + searchForm = <SearchBox/>; } return ( <div className='post-right__container'> - <FileUploadOverlay overlayType='right' /> + <FileUploadOverlay overlayType='right'/> <div className='search-bar__container sidebar--right__search-header'>{searchForm}</div> <div className='sidebar-right__body'> <RhsHeaderPost diff --git a/web/react/components/search_bar.jsx b/web/react/components/search_bar.jsx index f7cb1b8f2..1cdd09cc8 100644 --- a/web/react/components/search_bar.jsx +++ b/web/react/components/search_bar.jsx @@ -169,7 +169,7 @@ class SearchBar extends React.Component { style={{overflow: 'visible'}} autoComplete='off' > - <span className='glyphicon glyphicon-search sidebar__search-icon' /> + <span className='glyphicon glyphicon-search sidebar__search-icon'/> <SuggestionBox ref='search' className='form-control search-bar' diff --git a/web/react/components/search_results.jsx b/web/react/components/search_results.jsx index 12c066734..d10c5be27 100644 --- a/web/react/components/search_results.jsx +++ b/web/react/components/search_results.jsx @@ -97,7 +97,7 @@ export default class SearchResults extends React.Component { var currentId = UserStore.getCurrentId(); var searchForm = null; if (currentId) { - searchForm = <SearchBox />; + searchForm = <SearchBox/>; } var noResults = (!results || !results.order || !results.order.length); var searchTerm = SearchStore.getSearchTerm(); @@ -151,7 +151,7 @@ export default class SearchResults extends React.Component { <div className='sidebar--right__content'> <div className='search-bar__container sidebar--right__search-header'>{searchForm}</div> <div className='sidebar-right__body'> - <SearchResultsHeader isMentionSearch={this.props.isMentionSearch} /> + <SearchResultsHeader isMentionSearch={this.props.isMentionSearch}/> <div id='search-items-container' className='search-items-container' diff --git a/web/react/components/search_results_item.jsx b/web/react/components/search_results_item.jsx index d3533037f..3363c97f7 100644 --- a/web/react/components/search_results_item.jsx +++ b/web/react/components/search_results_item.jsx @@ -60,7 +60,7 @@ export default class SearchResultsItem extends React.Component { return ( <div className='search-item__container'> <div className='date-separator'> - <hr className='separator__hr' /> + <hr className='separator__hr'/> <div className='separator__text'> <FormattedDate value={this.props.post.create_at} @@ -84,7 +84,7 @@ export default class SearchResultsItem extends React.Component { </div> <div> <ul className='post__header'> - <li className='col__name'><strong><UserProfile userId={this.props.post.user_id} /></strong></li> + <li className='col__name'><strong><UserProfile userId={this.props.post.user_id}/></strong></li> <li className='col'> <time className='search-item-time'> <FormattedDate diff --git a/web/react/components/setting_item_max.jsx b/web/react/components/setting_item_max.jsx index ac750614b..70f011d26 100644 --- a/web/react/components/setting_item_max.jsx +++ b/web/react/components/setting_item_max.jsx @@ -61,7 +61,7 @@ export default class SettingItemMax extends React.Component { {extraInfo} </li> <li className='setting-list-item'> - <hr /> + <hr/> {serverError} {clientError} {submit} diff --git a/web/react/components/settings_sidebar.jsx b/web/react/components/settings_sidebar.jsx index 271ea9a41..90c0e8435 100644 --- a/web/react/components/settings_sidebar.jsx +++ b/web/react/components/settings_sidebar.jsx @@ -40,7 +40,7 @@ export default class SettingsSidebar extends React.Component { href='#' onClick={this.handleClick.bind(null, tab)} > - <i className={tab.icon} /> + <i className={tab.icon}/> {tab.uiName} </a> </li> diff --git a/web/react/components/sidebar_right.jsx b/web/react/components/sidebar_right.jsx index ee247265d..b81c0d099 100644 --- a/web/react/components/sidebar_right.jsx +++ b/web/react/components/sidebar_right.jsx @@ -87,6 +87,7 @@ export default class SidebarRight extends React.Component { $('.sidebar__overlay').remove(); }); }, 500);*/ + return null; } componentDidUpdate() { this.doStrangeThings(); @@ -115,7 +116,7 @@ export default class SidebarRight extends React.Component { var content = ''; if (this.state.search_visible) { - content = <SearchResults isMentionSearch={this.state.is_mention_search} />; + content = <SearchResults isMentionSearch={this.state.is_mention_search}/>; } else if (this.state.post_right_visible) { content = ( <RhsThread diff --git a/web/react/components/signup_team.jsx b/web/react/components/signup_team.jsx index 098e9f65a..5e8ae117d 100644 --- a/web/react/components/signup_team.jsx +++ b/web/react/components/signup_team.jsx @@ -130,21 +130,21 @@ export default class TeamSignUp extends React.Component { return ( <div> {teamListing} - <EmailSignUpPage /> + <EmailSignUpPage/> </div> ); } else if (this.state.page === 'gitlab') { return ( <div> {teamListing} - <SSOSignupPage service={Constants.GITLAB_SERVICE} /> + <SSOSignupPage service={Constants.GITLAB_SERVICE}/> </div> ); } else if (this.state.page === 'google') { return ( <div> {teamListing} - <SSOSignupPage service={Constants.GOOGLE_SERVICE} /> + <SSOSignupPage service={Constants.GOOGLE_SERVICE}/> </div> ); } else if (this.state.page === 'none') { @@ -157,6 +157,8 @@ export default class TeamSignUp extends React.Component { </div> ); } + + return null; } } diff --git a/web/react/components/signup_team_confirm.jsx b/web/react/components/signup_team_confirm.jsx index de83285db..290d8e503 100644 --- a/web/react/components/signup_team_confirm.jsx +++ b/web/react/components/signup_team_confirm.jsx @@ -4,10 +4,6 @@ import {FormattedMessage, FormattedHTMLMessage} from 'mm-intl'; export default class SignupTeamConfirm extends React.Component { - constructor(props) { - super(props); - } - render() { return ( <div className='signup-team__container'> diff --git a/web/react/components/signup_user_complete.jsx b/web/react/components/signup_user_complete.jsx index b770a2a2c..740a7b166 100644 --- a/web/react/components/signup_user_complete.jsx +++ b/web/react/components/signup_user_complete.jsx @@ -254,7 +254,7 @@ class SignupUserComplete extends React.Component { key='gitlab' href={'/' + this.props.teamName + '/signup/gitlab' + window.location.search} > - <span className='icon' /> + <span className='icon'/> <span> <FormattedMessage id='signup_user_completed.gitlab' @@ -272,7 +272,7 @@ class SignupUserComplete extends React.Component { key='google' href={'/' + this.props.teamName + '/signup/google' + window.location.search} > - <span className='icon' /> + <span className='icon'/> <span> <FormattedMessage id='signup_user_completed.google' diff --git a/web/react/components/suggestion/at_mention_provider.jsx b/web/react/components/suggestion/at_mention_provider.jsx index 50231ad15..c4e1314c9 100644 --- a/web/react/components/suggestion/at_mention_provider.jsx +++ b/web/react/components/suggestion/at_mention_provider.jsx @@ -24,7 +24,7 @@ class AtMentionSuggestion extends React.Component { defaultMessage='Notifies everyone in the team' /> ); - icon = <i className='mention-img fa fa-users fa-2x' />; + icon = <i className='mention-img fa fa-users fa-2x'/>; } else if (item.username === 'channel') { username = 'channel'; description = ( @@ -33,7 +33,7 @@ class AtMentionSuggestion extends React.Component { defaultMessage='Notifies everyone in the channel' /> ); - icon = <i className='mention-img fa fa-users fa-2x' />; + icon = <i className='mention-img fa fa-users fa-2x'/>; } else { username = item.username; description = Utils.getFullName(item); diff --git a/web/react/components/suggestion/suggestion_box.jsx b/web/react/components/suggestion/suggestion_box.jsx index 57a33c24a..ea9f835eb 100644 --- a/web/react/components/suggestion/suggestion_box.jsx +++ b/web/react/components/suggestion/suggestion_box.jsx @@ -140,7 +140,7 @@ export default class SuggestionBox extends React.Component { return ( <div> {textbox} - <SuggestionListComponent suggestionId={this.suggestionId} /> + <SuggestionListComponent suggestionId={this.suggestionId}/> </div> ); } diff --git a/web/react/components/team_export_tab.jsx b/web/react/components/team_export_tab.jsx index 8330637d8..12743d9e3 100644 --- a/web/react/components/team_export_tab.jsx +++ b/web/react/components/team_export_tab.jsx @@ -36,7 +36,7 @@ export default class TeamExportTab extends React.Component { case 'in-progress': messageSection = ( <p className='confirm-import alert alert-warning'> - <i className='fa fa-spinner fa-pulse' /> + <i className='fa fa-spinner fa-pulse'/> <FormattedMessage id='team_export_tab.exporting' defaultMessage=' Exporting...' @@ -47,7 +47,7 @@ export default class TeamExportTab extends React.Component { case 'ready': messageSection = ( <p className='confirm-import alert alert-success'> - <i className='fa fa-check' /> + <i className='fa fa-check'/> <FormattedMessage id='team_export_tab.ready' defaultMessage=' Ready for ' @@ -67,7 +67,7 @@ export default class TeamExportTab extends React.Component { case 'failure': messageSection = ( <p className='confirm-import alert alert-warning'> - <i className='fa fa-warning' /> + <i className='fa fa-warning'/> <FormattedMessage id='team_export_tab.unable' defaultMessage=' Unable to export: {error}' diff --git a/web/react/components/team_import_tab.jsx b/web/react/components/team_import_tab.jsx index adf990672..828e9fc4e 100644 --- a/web/react/components/team_import_tab.jsx +++ b/web/react/components/team_import_tab.jsx @@ -79,7 +79,7 @@ class TeamImportTab extends React.Component { case 'done': messageSection = ( <p className='confirm-import alert alert-success'> - <i className='fa fa-check' /> + <i className='fa fa-check'/> <FormattedMessage id='team_import_tab.successful' defaultMessage=' Import successful: ' @@ -99,7 +99,7 @@ class TeamImportTab extends React.Component { case 'fail': messageSection = ( <p className='confirm-import alert alert-warning'> - <i className='fa fa-warning' /> + <i className='fa fa-warning'/> <FormattedMessage id='team_import_tab.failure' defaultMessage=' Import failure: ' diff --git a/web/react/components/team_members_modal.jsx b/web/react/components/team_members_modal.jsx index 92adb6e2a..8ac435742 100644 --- a/web/react/components/team_members_modal.jsx +++ b/web/react/components/team_members_modal.jsx @@ -56,7 +56,7 @@ export default class TeamMembersModal extends React.Component { </Modal.Header> <Modal.Body ref='modalBody'> <div className='team-member-list'> - <MemberListTeam /> + <MemberListTeam/> </div> </Modal.Body> <Modal.Footer> diff --git a/web/react/components/team_settings.jsx b/web/react/components/team_settings.jsx index bbcedb5dd..e3207d573 100644 --- a/web/react/components/team_settings.jsx +++ b/web/react/components/team_settings.jsx @@ -55,7 +55,7 @@ export default class TeamSettings extends React.Component { case 'export': result = ( <div> - <ExportTab /> + <ExportTab/> </div> ); break; diff --git a/web/react/components/team_signup_choose_auth.jsx b/web/react/components/team_signup_choose_auth.jsx index 2dc67e92e..8c98c5538 100644 --- a/web/react/components/team_signup_choose_auth.jsx +++ b/web/react/components/team_signup_choose_auth.jsx @@ -23,7 +23,7 @@ export default class ChooseAuthPage extends React.Component { }.bind(this) } > - <span className='icon' /> + <span className='icon'/> <span> <FormattedMessage id='choose_auth_page.gitlabCreate' @@ -47,7 +47,7 @@ export default class ChooseAuthPage extends React.Component { } } > - <span className='icon' /> + <span className='icon'/> <span> <FormattedMessage id='choose_auth_page.googleCreate' @@ -71,7 +71,7 @@ export default class ChooseAuthPage extends React.Component { }.bind(this) } > - <span className='fa fa-envelope' /> + <span className='fa fa-envelope'/> <span> <FormattedMessage id='choose_auth_page.emailCreate' diff --git a/web/react/components/team_signup_send_invites_page.jsx b/web/react/components/team_signup_send_invites_page.jsx index 343db13e8..55cfe5114 100644 --- a/web/react/components/team_signup_send_invites_page.jsx +++ b/web/react/components/team_signup_send_invites_page.jsx @@ -183,7 +183,7 @@ export default class TeamSignupSendInvitesPage extends React.Component { <FormattedMessage id='team_signup_send_invites.next' defaultMessage='Next' - /><i className='glyphicon glyphicon-chevron-right' /> + /><i className='glyphicon glyphicon-chevron-right'/> </button> </div> </form> diff --git a/web/react/components/team_signup_welcome_page.jsx b/web/react/components/team_signup_welcome_page.jsx index 18951be72..9939c3ffd 100644 --- a/web/react/components/team_signup_welcome_page.jsx +++ b/web/react/components/team_signup_welcome_page.jsx @@ -150,7 +150,7 @@ class TeamSignupWelcomePage extends React.Component { id='team_signup_welcome.confirm' defaultMessage='Please confirm your email address:' /> - <br /> + <br/> <div className='inner__content'> <div className='block--gray'>{this.props.state.team.email}</div> </div> @@ -176,7 +176,7 @@ class TeamSignupWelcomePage extends React.Component { </button> {storageError} </div> - <hr /> + <hr/> <div className={emailDivContainerClass}> <div className={emailDivClass}> <div className='row'> diff --git a/web/react/components/time_since.jsx b/web/react/components/time_since.jsx index 1560d2469..d5891cc57 100644 --- a/web/react/components/time_since.jsx +++ b/web/react/components/time_since.jsx @@ -10,9 +10,6 @@ var Tooltip = ReactBootstrap.Tooltip; var OverlayTrigger = ReactBootstrap.OverlayTrigger; export default class TimeSince extends React.Component { - constructor(props) { - super(props); - } componentDidMount() { this.intervalId = setInterval(() => { this.forceUpdate(); @@ -51,7 +48,7 @@ export default class TimeSince extends React.Component { overlay={tooltip} > <time className='post__time'> - <FormattedRelative value={this.props.eventTime} /> + <FormattedRelative value={this.props.eventTime}/> </time> </OverlayTrigger> ); diff --git a/web/react/components/toggle_modal_button.jsx b/web/react/components/toggle_modal_button.jsx index ce8ff3f60..10f9a4736 100644 --- a/web/react/components/toggle_modal_button.jsx +++ b/web/react/components/toggle_modal_button.jsx @@ -22,7 +22,7 @@ export default class ModalToggleButton extends React.Component { } render() { - const {children, dialogType, dialogProps, onClick, ...props} = this.props; // eslint-disable-line no-redeclare + const {children, dialogType, dialogProps, onClick, ...props} = this.props; // eslint-disable-line no-use-before-define // allow callers to provide an onClick which will be called before the modal is shown let clickHandler = this.show; diff --git a/web/react/components/tutorial/tutorial_intro_screens.jsx b/web/react/components/tutorial/tutorial_intro_screens.jsx index 78cfb7b60..2bacdeb28 100644 --- a/web/react/components/tutorial/tutorial_intro_screens.jsx +++ b/web/react/components/tutorial/tutorial_intro_screens.jsx @@ -58,6 +58,7 @@ export default class TutorialIntroScreens extends React.Component { case 2: return this.createScreenThree(); } + return null; } createScreenOne() { const circles = this.createCircles(); diff --git a/web/react/components/unread_channel_indicator.jsx b/web/react/components/unread_channel_indicator.jsx index 509ac9e4d..f897cdea3 100644 --- a/web/react/components/unread_channel_indicator.jsx +++ b/web/react/components/unread_channel_indicator.jsx @@ -4,9 +4,6 @@ // Indicator for the left sidebar which indicate if there's unread posts in a channel that is not shown // because it is either above or below the screen export default class UnreadChannelIndicator extends React.Component { - constructor(props) { - super(props); - } render() { let displayValue = 'none'; if (this.props.show) { diff --git a/web/react/components/user_settings/user_settings_general.jsx b/web/react/components/user_settings/user_settings_general.jsx index cd229775f..2f2116c2a 100644 --- a/web/react/components/user_settings/user_settings_general.jsx +++ b/web/react/components/user_settings/user_settings_general.jsx @@ -22,7 +22,7 @@ const holders = defineMessages({ }, usernameRestrictions: { id: 'user.settings.general.usernameRestrictions', - defaultMessage: "'Username must begin with a letter, and contain between {min} to {max} lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'." + defaultMessage: "Username must begin with a letter, and contain between {min} to {max} lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'." }, validEmail: { id: 'user.settings.general.validEmail', diff --git a/web/react/components/user_settings/user_settings_integrations.jsx b/web/react/components/user_settings/user_settings_integrations.jsx index 07d5230d1..e4f460a6d 100644 --- a/web/react/components/user_settings/user_settings_integrations.jsx +++ b/web/react/components/user_settings/user_settings_integrations.jsx @@ -57,7 +57,7 @@ class UserSettingsIntegrationsTab extends React.Component { if (global.window.mm_config.EnableIncomingWebhooks === 'true') { if (this.props.activeSection === 'incoming-hooks') { inputs.push( - <ManageIncomingHooks key='incoming-hook-ui' /> + <ManageIncomingHooks key='incoming-hook-ui'/> ); incomingHooksSection = ( @@ -88,7 +88,7 @@ class UserSettingsIntegrationsTab extends React.Component { if (global.window.mm_config.EnableOutgoingWebhooks === 'true') { if (this.props.activeSection === 'outgoing-hooks') { inputs.push( - <ManageOutgoingHooks key='outgoing-hook-ui' /> + <ManageOutgoingHooks key='outgoing-hook-ui'/> ); outgoingHooksSection = ( @@ -119,7 +119,7 @@ class UserSettingsIntegrationsTab extends React.Component { if (global.window.mm_config.EnableCommands === 'true') { if (this.props.activeSection === 'command-hooks') { inputs.push( - <ManageCommandHooks key='command-hook-ui' /> + <ManageCommandHooks key='command-hook-ui'/> ); commandHooksSection = ( diff --git a/web/react/components/user_settings/user_settings_modal.jsx b/web/react/components/user_settings/user_settings_modal.jsx index 5442f7ac4..80d03d88e 100644 --- a/web/react/components/user_settings/user_settings_modal.jsx +++ b/web/react/components/user_settings/user_settings_modal.jsx @@ -111,12 +111,13 @@ class UserSettingsModal extends React.Component { this.afterConfirm = () => this.handleHide(); this.showConfirmModal(); - return false; + return; } this.resetTheme(); this.deactivateTab(); this.props.onModalDismissed(); + return; } // called after the dialog is fully hidden and faded out @@ -295,7 +296,12 @@ class UserSettingsModal extends React.Component { closeModal={this.closeModal} collapseModal={this.collapseModal} setEnforceFocus={(enforceFocus) => this.setState({enforceFocus})} - setRequireConfirm={(requireConfirm) => this.requireConfirm = requireConfirm} + setRequireConfirm={ + (requireConfirm) => { + this.requireConfirm = requireConfirm; + return; + } + } /> </div> </div> diff --git a/web/react/components/user_settings/user_settings_notifications.jsx b/web/react/components/user_settings/user_settings_notifications.jsx index 786e53f10..ee9febb8e 100644 --- a/web/react/components/user_settings/user_settings_notifications.jsx +++ b/web/react/components/user_settings/user_settings_notifications.jsx @@ -445,7 +445,7 @@ class NotificationsTab extends React.Component { title={formatMessage(holders.desktopSounds)} describe={describe} updateSection={handleUpdateSoundSection} - disableOpen = {!this.state.soundNeeded} + disableOpen={!this.state.soundNeeded} /> ); } @@ -826,4 +826,4 @@ NotificationsTab.propTypes = { collapseModal: React.PropTypes.func.isRequired }; -export default injectIntl(NotificationsTab);
\ No newline at end of file +export default injectIntl(NotificationsTab); diff --git a/web/react/components/view_image.jsx b/web/react/components/view_image.jsx index 90885e495..713fbf80b 100644 --- a/web/react/components/view_image.jsx +++ b/web/react/components/view_image.jsx @@ -203,7 +203,9 @@ class ViewImageModal extends React.Component { window.open(serverData.public_link); } }, - () => {} + () => { + //Do Nothing on error + } ); } @@ -383,6 +385,11 @@ function LoadingImagePreview({progress, loading}) { ); } +LoadingImagePreview.propTypes = { + progress: React.PropTypes.number, + loading: React.PropTypes.string +}; + function ImagePreview({filename, fileUrl, fileInfo, maxHeight}) { let previewUrl; if (fileInfo.has_preview_image) { @@ -405,4 +412,11 @@ function ImagePreview({filename, fileUrl, fileInfo, maxHeight}) { ); } -export default injectIntl(ViewImageModal);
\ No newline at end of file +ImagePreview.propTypes = { + filename: React.PropTypes.string.isRequired, + fileUrl: React.PropTypes.string.isRequired, + fileInfo: React.PropTypes.object.isRequired, + maxHeight: React.PropTypes.number.isRequired +}; + +export default injectIntl(ViewImageModal); diff --git a/web/react/components/view_image_popover_bar.jsx b/web/react/components/view_image_popover_bar.jsx index 97671b845..819df76d8 100644 --- a/web/react/components/view_image_popover_bar.jsx +++ b/web/react/components/view_image_popover_bar.jsx @@ -4,9 +4,6 @@ import {FormattedMessage} from 'mm-intl'; export default class ViewImagePopoverBar extends React.Component { - constructor(props) { - super(props); - } render() { var publicLink = ''; if (global.window.mm_config.EnablePublicLink === 'true') { diff --git a/web/react/components/youtube_video.jsx b/web/react/components/youtube_video.jsx index bf3c43840..fae846afb 100644 --- a/web/react/components/youtube_video.jsx +++ b/web/react/components/youtube_video.jsx @@ -94,6 +94,7 @@ export default class YoutubeVideo extends React.Component { receivedYoutubeData: true, title: metadata.title }); + return null; } play() { diff --git a/web/react/package.json b/web/react/package.json index 5fc2f2851..07ffa0cdf 100644 --- a/web/react/package.json +++ b/web/react/package.json @@ -3,10 +3,10 @@ "version": "0.0.1", "private": true, "dependencies": { - "autolinker": "0.22.0", - "fastclick": "^1.0.6", + "autolinker": "0.24.0", + "fastclick": "1.0.6", "flux": "2.1.1", - "highlight.js": "8.9.1", + "highlight.js": "9.1.0", "keymirror": "0.1.1", "marked": "mattermost/marked#cb85e5cc81bc7937dbb73c3c53d9532b1b97e3ca", "mm-intl": "mattermost/mm-intl#805442fd474fa40cd586ddeda404dbbe8e60626d", @@ -14,18 +14,18 @@ "twemoji": "1.4.1" }, "devDependencies": { - "babel-eslint": "4.1.7", - "babel-plugin-transform-runtime": "6.1.4", - "babel-preset-es2015": "6.1.18", - "babel-preset-react": "6.1.18", - "babel-preset-stage-0": "6.1.18", + "babel-eslint": "5.0.0", + "babel-plugin-transform-runtime": "6.5.2", + "babel-preset-es2015": "6.5.0", + "babel-preset-react": "6.5.0", + "babel-preset-stage-0": "6.5.0", "babelify": "7.2.0", - "browserify": "12.0.1", - "eslint": "1.9.0", - "eslint-plugin-react": "3.9.0", + "browserify": "13.0.0", + "eslint": "2.2.0", + "eslint-plugin-react": "4.0.0", "exorcist": "0.4.0", "uglify-js": "2.6.1", - "watchify": "3.6.1" + "watchify": "3.7.0" }, "scripts": { "check": "", diff --git a/web/react/pages/admin_console.jsx b/web/react/pages/admin_console.jsx index 3f4c39934..989936d9e 100644 --- a/web/react/pages/admin_console.jsx +++ b/web/react/pages/admin_console.jsx @@ -56,7 +56,7 @@ class Root extends React.Component { tab={this.props.map.ActiveTab} teamId={this.props.map.TeamId} /> - <SelectTeamModal /> + <SelectTeamModal/> </div> </IntlProvider> ); @@ -65,7 +65,7 @@ class Root extends React.Component { global.window.setup_admin_console_page = function setup(props) { ReactDOM.render( - <Root map={props} />, + <Root map={props}/>, document.getElementById('admin_controller') ); }; diff --git a/web/react/pages/authorize.jsx b/web/react/pages/authorize.jsx index 7474332ce..20fea19f0 100644 --- a/web/react/pages/authorize.jsx +++ b/web/react/pages/authorize.jsx @@ -29,6 +29,7 @@ class Root extends React.Component { translations: data, loaded: true }); + return; }, () => { this.setState({ @@ -64,7 +65,7 @@ class Root extends React.Component { global.window.setup_authorize_page = function setup(props) { ReactDOM.render( - <Root map={props} />, + <Root map={props}/>, document.getElementById('authorize') ); }; diff --git a/web/react/pages/channel.jsx b/web/react/pages/channel.jsx index bd7c7c69b..bc78c049c 100644 --- a/web/react/pages/channel.jsx +++ b/web/react/pages/channel.jsx @@ -8,7 +8,6 @@ import * as Client from '../utils/client.jsx'; import GetPostLinkModal from '../components/get_post_link_modal.jsx'; import GetTeamInviteLinkModal from '../components/get_team_invite_link_modal.jsx'; -import RenameChannelModal from '../components/rename_channel_modal.jsx'; import EditPostModal from '../components/edit_post_modal.jsx'; import DeletePostModal from '../components/delete_post_modal.jsx'; import MoreChannelsModal from '../components/more_channels.jsx'; @@ -68,18 +67,16 @@ class Root extends React.Component { <ChannelLoader/> <ErrorBar/> <ChannelView/> - - <GetPostLinkModal /> - <GetTeamInviteLinkModal /> - <InviteMemberModal /> - <ImportThemeModal /> - <TeamSettingsModal /> - <RenameChannelModal /> - <MoreChannelsModal /> - <EditPostModal /> - <DeletePostModal /> - <RemovedFromChannelModal /> - <RegisterAppModal /> + <GetPostLinkModal/> + <GetTeamInviteLinkModal/> + <InviteMemberModal/> + <ImportThemeModal/> + <TeamSettingsModal/> + <MoreChannelsModal/> + <EditPostModal/> + <DeletePostModal/> + <RemovedFromChannelModal/> + <RegisterAppModal/> </div> </IntlProvider> ); @@ -94,7 +91,7 @@ global.window.setup_channel_page = function setup(props, team, channel) { } ReactDOM.render( - <Root map={props} />, + <Root map={props}/>, document.getElementById('channel_view') ); }; diff --git a/web/react/pages/claim_account.jsx b/web/react/pages/claim_account.jsx index 7c6af73ca..abbf72ea3 100644 --- a/web/react/pages/claim_account.jsx +++ b/web/react/pages/claim_account.jsx @@ -62,7 +62,7 @@ class Root extends React.Component { global.window.setup_claim_account_page = function setup(props) { ReactDOM.render( - <Root map={props} />, + <Root map={props}/>, document.getElementById('claim') ); };
\ No newline at end of file diff --git a/web/react/pages/docs.jsx b/web/react/pages/docs.jsx index 2f5d4db55..2e47e3e6a 100644 --- a/web/react/pages/docs.jsx +++ b/web/react/pages/docs.jsx @@ -48,7 +48,7 @@ class Root extends React.Component { locale={this.props.map.Locale} messages={this.state.translations} > - <Docs site={this.props.map.Site} /> + <Docs site={this.props.map.Site}/> </IntlProvider> ); } @@ -58,7 +58,7 @@ global.window.mm_user = global.window.mm_user || {}; global.window.setup_documentation_page = function setup(props) { ReactDOM.render( - <Root map={props} />, + <Root map={props}/>, document.getElementById('docs') ); }; diff --git a/web/react/pages/find_team.jsx b/web/react/pages/find_team.jsx index ee2cf0de1..93394fcde 100644 --- a/web/react/pages/find_team.jsx +++ b/web/react/pages/find_team.jsx @@ -48,7 +48,7 @@ class Root extends React.Component { locale={this.props.map.Locale} messages={this.state.translations} > - <FindTeam /> + <FindTeam/> </IntlProvider> ); } @@ -56,7 +56,7 @@ class Root extends React.Component { global.window.setup_find_team_page = function setup(props) { ReactDOM.render( - <Root map={props} />, + <Root map={props}/>, document.getElementById('find-team') ); };
\ No newline at end of file diff --git a/web/react/pages/login.jsx b/web/react/pages/login.jsx index 38852ad7c..ec9080945 100644 --- a/web/react/pages/login.jsx +++ b/web/react/pages/login.jsx @@ -60,7 +60,7 @@ class Root extends React.Component { global.window.setup_login_page = function setup(props) { ReactDOM.render( - <Root map={props} />, + <Root map={props}/>, document.getElementById('login') ); };
\ No newline at end of file diff --git a/web/react/pages/password_reset.jsx b/web/react/pages/password_reset.jsx index 23bbf2691..7caff5034 100644 --- a/web/react/pages/password_reset.jsx +++ b/web/react/pages/password_reset.jsx @@ -62,7 +62,7 @@ class Root extends React.Component { global.window.setup_password_reset_page = function setup(props) { ReactDOM.render( - <Root map={props} />, + <Root map={props}/>, document.getElementById('reset') ); }; diff --git a/web/react/pages/signup_team.jsx b/web/react/pages/signup_team.jsx index c80b65580..f276c3ff7 100644 --- a/web/react/pages/signup_team.jsx +++ b/web/react/pages/signup_team.jsx @@ -49,7 +49,7 @@ class Root extends React.Component { locale={this.props.map.Locale} messages={this.state.translations} > - <SignupTeam teams={this.props.teams} /> + <SignupTeam teams={this.props.teams}/> </IntlProvider> ); } diff --git a/web/react/pages/signup_team_complete.jsx b/web/react/pages/signup_team_complete.jsx index 1bee4e598..8c237f698 100644 --- a/web/react/pages/signup_team_complete.jsx +++ b/web/react/pages/signup_team_complete.jsx @@ -60,7 +60,7 @@ class Root extends React.Component { global.window.setup_signup_team_complete_page = function setup(props) { ReactDOM.render( - <Root map={props} />, + <Root map={props}/>, document.getElementById('signup-team-complete') ); };
\ No newline at end of file diff --git a/web/react/pages/signup_team_confirm.jsx b/web/react/pages/signup_team_confirm.jsx index 9a536c92e..13c8f3fd0 100644 --- a/web/react/pages/signup_team_confirm.jsx +++ b/web/react/pages/signup_team_confirm.jsx @@ -58,7 +58,7 @@ class Root extends React.Component { global.window.setup_signup_team_confirm_page = function setup(props) { ReactDOM.render( - <Root map={props} />, + <Root map={props}/>, document.getElementById('signup-team-confirm') ); };
\ No newline at end of file diff --git a/web/react/pages/signup_user_complete.jsx b/web/react/pages/signup_user_complete.jsx index 6c761c1ee..a14f2140b 100644 --- a/web/react/pages/signup_user_complete.jsx +++ b/web/react/pages/signup_user_complete.jsx @@ -63,7 +63,7 @@ class Root extends React.Component { global.window.setup_signup_user_complete_page = function setup(props) { ReactDOM.render( - <Root map={props} />, + <Root map={props}/>, document.getElementById('signup-user-complete') ); };
\ No newline at end of file diff --git a/web/react/pages/verify.jsx b/web/react/pages/verify.jsx index 2fc619e58..6b336daa1 100644 --- a/web/react/pages/verify.jsx +++ b/web/react/pages/verify.jsx @@ -61,7 +61,7 @@ class Root extends React.Component { global.window.setupVerifyPage = function setup(props) { ReactDOM.render( - <Root map={props} />, + <Root map={props}/>, document.getElementById('verify') ); }; diff --git a/web/react/stores/modal_store.jsx b/web/react/stores/modal_store.jsx index 931443f62..5ea38030b 100644 --- a/web/react/stores/modal_store.jsx +++ b/web/react/stores/modal_store.jsx @@ -28,7 +28,7 @@ class ModalStoreClass extends EventEmitter { handleEventPayload(payload) { // toggle event handlers should accept a boolean show/hide value and can accept a map of arguments - const {type, value, ...args} = payload.action; //eslint-disable-line no-redeclare + const {type, value, ...args} = payload.action; //eslint-disable-line no-use-before-define switch (type) { case ActionTypes.TOGGLE_IMPORT_THEME_MODAL: diff --git a/web/react/stores/suggestion_store.jsx b/web/react/stores/suggestion_store.jsx index dd5c107e0..efd2b76ed 100644 --- a/web/react/stores/suggestion_store.jsx +++ b/web/react/stores/suggestion_store.jsx @@ -210,7 +210,7 @@ class SuggestionStore extends EventEmitter { } handleEventPayload(payload) { - const {type, id, ...other} = payload.action; // eslint-disable-line no-redeclare + const {type, id, ...other} = payload.action; // eslint-disable-line no-use-before-define switch (type) { case ActionTypes.SUGGESTION_PRETEXT_CHANGED: diff --git a/web/react/utils/channel_intro_messages.jsx b/web/react/utils/channel_intro_messages.jsx index 1aca0467e..79e58147f 100644 --- a/web/react/utils/channel_intro_messages.jsx +++ b/web/react/utils/channel_intro_messages.jsx @@ -23,6 +23,7 @@ export function createChannelIntroMessage(channel) { } else if (channel.type === 'O' || channel.type === 'P') { return createStandardIntroMessage(channel); } + return null; } export function createDMIntroMessage(channel) { @@ -46,7 +47,7 @@ export function createDMIntroMessage(channel) { </div> <div className='channel-intro-profile'> <strong> - <UserProfile userId={teammate.id} /> + <UserProfile userId={teammate.id}/> </strong> </div> <p className='channel-intro-text'> diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx index 992337671..81bdb7293 100644 --- a/web/react/utils/client.jsx +++ b/web/react/utils/client.jsx @@ -1430,7 +1430,7 @@ export function listIncomingHooks(success, error) { export function getAllPreferences(success, error) { $.ajax({ - url: `/api/v1/preferences/`, + url: '/api/v1/preferences/', dataType: 'json', type: 'GET', success, diff --git a/web/react/utils/emoticons.jsx b/web/react/utils/emoticons.jsx index 23a847969..18cce3bde 100644 --- a/web/react/utils/emoticons.jsx +++ b/web/react/utils/emoticons.jsx @@ -157,5 +157,5 @@ export function getImagePathForEmoticon(name) { if (name) { return `/static/images/emoji/${name}.png`; } - return `/static/images/emoji`; + return '/static/images/emoji'; } diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index 2b946d81f..a4d2515e2 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -142,6 +142,7 @@ export function getCookie(name) { if (parts.length === 2) { return parts.pop().split(';').shift(); } + return ''; } var requestedNotificationPermission = false; @@ -188,7 +189,10 @@ export function ding() { var audio = new Audio('/static/images/bing.mp3'); audio.play(); canDing = false; - setTimeout(() => canDing = true, 3000); + setTimeout(() => { + canDing = true; + return; + }, 3000); } } diff --git a/web/sass-files/sass/partials/_perfect-scrollbar.scss b/web/sass-files/sass/partials/_perfect-scrollbar.scss index 0e0967d81..de88112c9 100755..100644 --- a/web/sass-files/sass/partials/_perfect-scrollbar.scss +++ b/web/sass-files/sass/partials/_perfect-scrollbar.scss @@ -1,23 +1,31 @@ @charset "UTF-8"; +/* perfect-scrollbar v0.6.10 */ .ps-container { - overflow: hidden !important; } - .ps-container.ps-active-x > .ps-scrollbar-x-rail, .ps-container.ps-active-y > .ps-scrollbar-y-rail { - display: block; } + -ms-touch-action: none; + touch-action: none; + overflow: hidden !important; + -ms-overflow-style: none; } + @supports (-ms-overflow-style: none) { + .ps-container { + overflow: auto !important; } } + @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .ps-container { + overflow: auto !important; } } + .ps-container.ps-active-x > .ps-scrollbar-x-rail, + .ps-container.ps-active-y > .ps-scrollbar-y-rail { + display: block; + background-color: transparent; } .ps-container.ps-in-scrolling { - } + } .ps-container.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail { background-color: #eee; - opacity: 0.9; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=90)"; - filter: alpha(opacity=90); } + opacity: 0.9; } .ps-container.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail > .ps-scrollbar-x { background-color: #999; } .ps-container.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail { background-color: #eee; - opacity: 0.9; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=90)"; - filter: alpha(opacity=90); } + opacity: 0.9; } .ps-container.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail > .ps-scrollbar-y { background-color: #999; } .ps-container > .ps-scrollbar-x-rail { @@ -26,11 +34,8 @@ /* please don't change 'position' */ -webkit-border-radius: 4px; -moz-border-radius: 4px; - -ms-border-radius: 4px; border-radius: 4px; opacity: 0; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; - filter: alpha(opacity=0); -webkit-transition: background-color .2s linear, opacity .2s linear; -moz-transition: background-color .2s linear, opacity .2s linear; -o-transition: background-color .2s linear, opacity .2s linear; @@ -44,7 +49,6 @@ background-color: #aaa; -webkit-border-radius: 4px; -moz-border-radius: 4px; - -ms-border-radius: 4px; border-radius: 4px; -webkit-transition: background-color .2s linear; -moz-transition: background-color .2s linear; @@ -59,11 +63,8 @@ /* please don't change 'position' */ -webkit-border-radius: 4px; -moz-border-radius: 4px; - -ms-border-radius: 4px; border-radius: 4px; opacity: 0; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; - filter: alpha(opacity=0); -webkit-transition: background-color .2s linear, opacity .2s linear; -moz-transition: background-color .2s linear, opacity .2s linear; -o-transition: background-color .2s linear, opacity .2s linear; @@ -77,7 +78,6 @@ background-color: #aaa; -webkit-border-radius: 4px; -moz-border-radius: 4px; - -ms-border-radius: 4px; border-radius: 4px; -webkit-transition: background-color .2s linear; -moz-transition: background-color .2s linear; @@ -87,36 +87,27 @@ /* there must be 'right' for ps-scrollbar-y */ width: 8px; } .ps-container:hover.ps-in-scrolling { - } + } .ps-container:hover.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail { background-color: #eee; - opacity: 0.9; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=90)"; - filter: alpha(opacity=90); } + opacity: 0.9; } .ps-container:hover.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail > .ps-scrollbar-x { background-color: #999; } .ps-container:hover.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail { background-color: #eee; - opacity: 0.9; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=90)"; - filter: alpha(opacity=90); } + opacity: 0.9; } .ps-container:hover.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail > .ps-scrollbar-y { background-color: #999; } - .ps-container:hover > .ps-scrollbar-x-rail, .ps-container:hover > .ps-scrollbar-y-rail { - opacity: 0.6; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; - filter: alpha(opacity=60); } + .ps-container:hover > .ps-scrollbar-x-rail, + .ps-container:hover > .ps-scrollbar-y-rail { + opacity: 0.6; } .ps-container:hover > .ps-scrollbar-x-rail:hover { background-color: #eee; - opacity: 0.9; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=90)"; - filter: alpha(opacity=90); } + opacity: 0.9; } .ps-container:hover > .ps-scrollbar-x-rail:hover > .ps-scrollbar-x { background-color: #999; } .ps-container:hover > .ps-scrollbar-y-rail:hover { background-color: #eee; - opacity: 0.9; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=90)"; - filter: alpha(opacity=90); } + opacity: 0.9; } .ps-container:hover > .ps-scrollbar-y-rail:hover > .ps-scrollbar-y { background-color: #999; } diff --git a/web/sass-files/sass/partials/_signup.scss b/web/sass-files/sass/partials/_signup.scss index 81fe037f7..e9c872a6e 100644 --- a/web/sass-files/sass/partials/_signup.scss +++ b/web/sass-files/sass/partials/_signup.scss @@ -5,6 +5,11 @@ line-height: 33px; padding: 0 1em 0.2em; background: #EEE; + + .fa { + margin-right: 5px; + } + } .signup-team__container { padding: 100px 0px 50px 0px; diff --git a/web/static/i18n/en.json b/web/static/i18n/en.json index 1dc0bdebc..a4c32e6e4 100644 --- a/web/static/i18n/en.json +++ b/web/static/i18n/en.json @@ -1,1278 +1,1277 @@ { - "about.teamEdtion": "Team Edition", + "about.close": "Close", + "about.date": "Build Date:", "about.enterpriseEdition": "Enterprise Edition", + "about.hash": "Build Hash:", "about.licensed": "Licensed by:", + "about.number": "Build Number:", + "about.teamEdtion": "Team Edition", "about.title": "About Mattermost", "about.version": "Version:", - "about.number": "Build Number:", - "about.date": "Build Date:", - "about.hash": "Build Hash:", - "about.close": "Close", "access_history.title": "Access History", - "activity_log_modal.iphoneNativeApp": "iPhone Native App", - "activity_log_modal.androidNativeApp": "Android Native App", - "activity_log_modal.android": "Android", - "activity_log.firstTime": "First time active: {date}, {time}", - "activity_log.os": "OS: {os}", + "activity_log.activeSessions": "Active Sessions", "activity_log.browser": "Browser: {browser}", - "activity_log.sessionId": "Session ID: {id}", - "activity_log.moreInfo": "More info", + "activity_log.firstTime": "First time active: {date}, {time}", "activity_log.lastActivity": "Last activity: {date}, {time}", "activity_log.logout": "Logout", - "activity_log.activeSessions": "Active Sessions", + "activity_log.moreInfo": "More info", + "activity_log.os": "OS: {os}", + "activity_log.sessionId": "Session ID: {id}", "activity_log.sessionsDescription": "Sessions are created when you log in with your email and password to a new browser on a device. Sessions let you use Mattermost for up to 30 days without having to log in again. If you want to log out sooner, use the 'Logout' button below to end a session.", - "admin.nav.switch": "Switch to {display_name}", - "admin.nav.logout": "Logout", - "admin.nav.help": "Help", - "admin.nav.report": "Report a Problem", - "admin.sidebarHeader.systemConsole": "System Console", - "admin.sidebar.loading": "Loading", - "admin.sidebar.rmTeamSidebar": "Remove team from sidebar menu", - "admin.sidebar.addTeamSidebar": "Add team from sidebar menu", - "admin.sidebar.users": "- Users", - "admin.sidebar.statistics": "- Statistics", - "admin.sidebar.ldap": "LDAP Settings", - "admin.sidebar.license": "Edition and License", - "admin.sidebar.audits": "Compliance and Auditing", - "admin.sidebar.reports": "SITE REPORTS", - "admin.sidebar.view_statistics": "View Statistics", - "admin.sidebar.settings": "SETTINGS", - "admin.sidebar.service": "Service Settings", - "admin.sidebar.team": "Team Settings", - "admin.sidebar.sql": "SQL Settings", - "admin.sidebar.email": "Email Settings", - "admin.sidebar.file": "File Settings", - "admin.sidebar.log": "Log Settings", - "admin.sidebar.rate_limit": "Rate Limit Settings", - "admin.sidebar.privacy": "Privacy Settings", - "admin.sidebar.gitlab": "GitLab Settings", - "admin.sidebar.support": "Legal and Support Settings", - "admin.sidebar.teams": "TEAMS ({count})", - "admin.sidebar.other": "OTHER", - "admin.sidebar.logs": "Logs", - "admin.analytics.totalUsers": "Total Users", - "admin.analytics.publicChannels": "Public Channels", - "admin.analytics.privateGroups": "Private Groups", - "admin.analytics.totalPosts": "Total Posts", - "admin.analytics.totalFilePosts": "Posts with Files", - "admin.analytics.totalHashtagPosts": "Posts with Hashtags", - "admin.analytics.totalIncomingWebhooks": "Incoming Webhooks", - "admin.analytics.totalOutgoingWebhooks": "Outgoing Webhooks", + "activity_log_modal.android": "Android", + "activity_log_modal.androidNativeApp": "Android Native App", + "activity_log_modal.iphoneNativeApp": "iPhone Native App", + "admin.analytics.activeUsers": "Active Users With Posts", "admin.analytics.channelTypes": "Channel Types", - "admin.analytics.textPosts": "Posts with Text-only", - "admin.analytics.postTypes": "Posts, Files and Hashtags", "admin.analytics.loading": "Loading...", "admin.analytics.meaningful": "Not enough data for a meaningful representation.", - "admin.analytics.activeUsers": "Active Users With Posts", - "admin.analytics.recentActive": "Recent Active Users", "admin.analytics.newlyCreated": "Newly Created Users", + "admin.analytics.postTypes": "Posts, Files and Hashtags", + "admin.analytics.privateGroups": "Private Groups", + "admin.analytics.publicChannels": "Public Channels", + "admin.analytics.recentActive": "Recent Active Users", + "admin.analytics.textPosts": "Posts with Text-only", "admin.analytics.title": "Statistics for {title}", - "admin.audits.title": "User Activity", + "admin.analytics.totalFilePosts": "Posts with Files", + "admin.analytics.totalHashtagPosts": "Posts with Hashtags", + "admin.analytics.totalIncomingWebhooks": "Incoming Webhooks", + "admin.analytics.totalOutgoingWebhooks": "Outgoing Webhooks", + "admin.analytics.totalPosts": "Total Posts", + "admin.analytics.totalUsers": "Total Users", "admin.audits.reload": "Reload", - "admin.email.notificationDisplayExample": "Ex: \"Mattermost Notification\", \"System\", \"No-Reply\"", - "admin.email.notificationEmailExample": "Ex: \"mattermost@yourcompany.com\", \"admin@yourcompany.com\"", - "admin.email.smtpUsernameExample": "Ex: \"admin@yourcompany.com\", \"AKIADTOVBGERKLCBV\"", - "admin.email.smtpPasswordExample": "Ex: \"yourpassword\", \"jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY\"", - "admin.email.smtpServerExample": "Ex: \"smtp.yourcompany.com\", \"email-smtp.us-east-1.amazonaws.com\"", - "admin.email.smtpPortExample": "Ex: \"25\", \"465\"", + "admin.audits.title": "User Activity", + "admin.email.allowEmailSignInDescription": "When true, Mattermost allows users to sign in using their email and password.", + "admin.email.allowEmailSignInTitle": "Allow Sign In With Email: ", + "admin.email.allowSignupDescription": "When true, Mattermost allows team creation and account signup using email and password. This value should be false only when you want to limit signup to a single-sign-on service like OAuth or LDAP.", + "admin.email.allowSignupTitle": "Allow Sign Up With Email: ", + "admin.email.allowUsernameSignInDescription": "When true, Mattermost allows users to sign in using their username and password. This setting is typically only used when email verification is disabled.", + "admin.email.allowUsernameSignInTitle": "Allow Sign In With Username: ", "admin.email.connectionSecurityNone": "None", - "admin.email.connectionSecurityTls": "TLS (Recommended)", + "admin.email.connectionSecurityNoneDescription": "Mattermost will send email over an unsecure connection.", "admin.email.connectionSecurityStart": "STARTTLS", - "admin.email.inviteSaltExample": "Ex \"bjlSR4QqkXFBr7TP4oDzlfZmcNuH9Yo\"", - "admin.email.passwordSaltExample": "Ex \"bjlSR4QqkXFBr7TP4oDzlfZmcNuH9Yo\"", - "admin.email.pushServerEx": "E.g.: \"http://push-test.mattermost.com\"", - "admin.email.testing": "Testing...", - "admin.email.saving": "Saving Config...", - "admin.email.emailSuccess": "No errors were reported while sending an email. Please check your inbox to make sure.", + "admin.email.connectionSecurityStartDescription": "Takes an existing insecure connection and attempts to upgrade it to a secure connection using TLS.", + "admin.email.connectionSecurityTest": "Test Connection", + "admin.email.connectionSecurityTitle": "Connection Security:", + "admin.email.connectionSecurityTls": "TLS (Recommended)", + "admin.email.connectionSecurityTlsDescription": "Encrypts the communication between Mattermost and your email server.", "admin.email.emailFail": "Connection unsuccessful: {error}", "admin.email.emailSettings": "Email Settings", - "admin.email.allowSignupTitle": "Allow Sign Up With Email: ", - "admin.email.true": "true", + "admin.email.emailSuccess": "No errors were reported while sending an email. Please check your inbox to make sure.", "admin.email.false": "false", - "admin.email.allowSignupDescription": "When true, Mattermost allows team creation and account signup using email and password. This value should be false only when you want to limit signup to a single-sign-on service like OAuth or LDAP.", - "admin.email.allowEmailSignInTitle": "Allow Sign In With Email: ", - "admin.email.allowEmailSignInDescription": "When true, Mattermost allows users to sign in using their email and password.", - "admin.email.allowUsernameSignInTitle": "Allow Sign In With Username: ", - "admin.email.allowUsernameSignInDescription": "When true, Mattermost allows users to sign in using their username and password. This setting is typically only used when email verification is disabled.", - "admin.email.notificationsTitle": "Send Email Notifications: ", - "admin.email.notificationsDescription": "Typically set to true in production. When true, Mattermost attempts to send email notifications. Developers may set this field to false to skip email setup for faster development.<br />Setting this to true removes the Preview Mode banner (requires logging out and logging back in after setting is changed).", - "admin.email.requireVerificationTitle": "Require Email Verification: ", - "admin.email.requireVerificationDescription": "Typically set to true in production. When true, Mattermost requires email verification after account creation prior to allowing login. Developers may set this field to false so skip sending verification emails for faster development.", - "admin.email.notificationDisplayTitle": "Notification Display Name:", + "admin.email.inviteSaltDescription": "32-character salt added to signing of email invites. Randomly generated on install. Click \"Re-Generate\" to create new salt.", + "admin.email.inviteSaltExample": "Ex \"bjlSR4QqkXFBr7TP4oDzlfZmcNuH9Yo\"", + "admin.email.inviteSaltTitle": "Invite Salt:", "admin.email.notificationDisplayDescription": "Display name on email account used when sending notification emails from Mattermost.", - "admin.email.notificationEmailTitle": "Notification Email Address:", + "admin.email.notificationDisplayExample": "Ex: \"Mattermost Notification\", \"System\", \"No-Reply\"", + "admin.email.notificationDisplayTitle": "Notification Display Name:", "admin.email.notificationEmailDescription": "Email address displayed on email account used when sending notification emails from Mattermost.", - "admin.email.smtpUsernameTitle": "SMTP Username:", - "admin.email.smtpUsernameDescription": " Obtain this credential from administrator setting up your email server.", - "admin.email.smtpPasswordTitle": "SMTP Password:", - "admin.email.smtpPasswordDescription": " Obtain this credential from administrator setting up your email server.", - "admin.email.smtpServerTitle": "SMTP Server:", - "admin.email.smtpServerDescription": "Location of SMTP email server.", - "admin.email.smtpPortTitle": "SMTP Port:", - "admin.email.smtpPortDescription": "Port of SMTP email server.", - "admin.email.connectionSecurityTitle": "Connection Security:", - "admin.email.connectionSecurityNoneDescription": "Mattermost will send email over an unsecure connection.", - "admin.email.connectionSecurityTlsDescription": "Encrypts the communication between Mattermost and your email server.", - "admin.email.connectionSecurityStartDescription": "Takes an existing insecure connection and attempts to upgrade it to a secure connection using TLS.", - "admin.email.connectionSecurityTest": "Test Connection", - "admin.email.inviteSaltTitle": "Invite Salt:", - "admin.email.inviteSaltDescription": "32-character salt added to signing of email invites. Randomly generated on install. Click \"Re-Generate\" to create new salt.", - "admin.email.regenerate": "Re-Generate", - "admin.email.passwordSaltTitle": "Password Reset Salt:", + "admin.email.notificationEmailExample": "Ex: \"mattermost@yourcompany.com\", \"admin@yourcompany.com\"", + "admin.email.notificationEmailTitle": "Notification Email Address:", + "admin.email.notificationsDescription": "Typically set to true in production. When true, Mattermost attempts to send email notifications. Developers may set this field to false to skip email setup for faster development.<br />Setting this to true removes the Preview Mode banner (requires logging out and logging back in after setting is changed).", + "admin.email.notificationsTitle": "Send Email Notifications: ", "admin.email.passwordSaltDescription": "32-character salt added to signing of password reset emails. Randomly generated on install. Click \"Re-Generate\" to create new salt.", - "admin.email.pushTitle": "Send Push Notifications: ", + "admin.email.passwordSaltExample": "Ex \"bjlSR4QqkXFBr7TP4oDzlfZmcNuH9Yo\"", + "admin.email.passwordSaltTitle": "Password Reset Salt:", "admin.email.pushDesc": "Typically set to true in production. When true, Mattermost attempts to send iOS and Android push notifications through the push notification server.", - "admin.email.pushServerTitle": "Push Notification Server:", "admin.email.pushServerDesc": "Location of Mattermost push notification service you can set up behind your firewall using https://github.com/mattermost/push-proxy. For testing you can use http://push-test.mattermost.com, which connects to the sample Mattermost iOS app in the public Apple AppStore. Please do not use test service for production deployments.", + "admin.email.pushServerEx": "E.g.: \"http://push-test.mattermost.com\"", + "admin.email.pushServerTitle": "Push Notification Server:", + "admin.email.pushTitle": "Send Push Notifications: ", + "admin.email.regenerate": "Re-Generate", + "admin.email.requireVerificationDescription": "Typically set to true in production. When true, Mattermost requires email verification after account creation prior to allowing login. Developers may set this field to false so skip sending verification emails for faster development.", + "admin.email.requireVerificationTitle": "Require Email Verification: ", "admin.email.save": "Save", + "admin.email.saving": "Saving Config...", + "admin.email.smtpPasswordDescription": " Obtain this credential from administrator setting up your email server.", + "admin.email.smtpPasswordExample": "Ex: \"yourpassword\", \"jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY\"", + "admin.email.smtpPasswordTitle": "SMTP Password:", + "admin.email.smtpPortDescription": "Port of SMTP email server.", + "admin.email.smtpPortExample": "Ex: \"25\", \"465\"", + "admin.email.smtpPortTitle": "SMTP Port:", + "admin.email.smtpServerDescription": "Location of SMTP email server.", + "admin.email.smtpServerExample": "Ex: \"smtp.yourcompany.com\", \"email-smtp.us-east-1.amazonaws.com\"", + "admin.email.smtpServerTitle": "SMTP Server:", + "admin.email.smtpUsernameDescription": " Obtain this credential from administrator setting up your email server.", + "admin.email.smtpUsernameExample": "Ex: \"admin@yourcompany.com\", \"AKIADTOVBGERKLCBV\"", + "admin.email.smtpUsernameTitle": "SMTP Username:", + "admin.email.testing": "Testing...", + "admin.email.true": "true", + "admin.gitab.clientSecretDescription": "Obtain this value via the instructions above for logging into GitLab.", + "admin.gitlab.EnableHtmlDesc": "<ol><li>Log in to your GitLab account and go to Applications -> Profile Settings.</li><li>Enter Redirect URIs \"<your-mattermost-url>/login/gitlab/complete\" (example: http://localhost:8065/login/gitlab/complete) and \"<your-mattermost-url>/signup/gitlab/complete\". </li><li>Then use \"Secret\" and \"Id\" fields from GitLab to complete the options below.</li><li>Complete the Endpoint URLs below. </li></ol>", + "admin.gitlab.authDescription": "Enter https://<your-gitlab-url>/oauth/authorize (example https://example.com:3000/oauth/authorize). Make sure you use HTTP or HTTPS in your URL depending on your server configuration.", + "admin.gitlab.authExample": "Ex \"\"", + "admin.gitlab.authTitle": "Auth Endpoint:", + "admin.gitlab.clientIdDescription": "Obtain this value via the instructions above for logging into GitLab", "admin.gitlab.clientIdExample": "Ex \"jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY\"", + "admin.gitlab.clientIdTitle": "Id:", "admin.gitlab.clientSecretExample": "Ex \"jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY\"", - "admin.gitlab.authExample": "Ex \"\"", - "admin.gitlab.tokenExample": "Ex \"\"", - "admin.gitlab.userExample": "Ex \"\"", - "admin.gitlab.saving": "Saving Config...", - "admin.gitlab.settingsTitle": "GitLab Settings", + "admin.gitlab.clientSecretTitle": "Secret:", + "admin.gitlab.enableDescription": "When true, Mattermost allows team creation and account signup using GitLab OAuth.", "admin.gitlab.enableTitle": "Enable Sign Up With GitLab: ", - "admin.gitlab.true": "true", "admin.gitlab.false": "false", - "admin.gitlab.enableDescription": "When true, Mattermost allows team creation and account signup using GitLab OAuth.", - "admin.gitlab.EnableHtmlDesc": "<ol><li>Log in to your GitLab account and go to Applications -> Profile Settings.</li><li>Enter Redirect URIs \"<your-mattermost-url>/login/gitlab/complete\" (example: http://localhost:8065/login/gitlab/complete) and \"<your-mattermost-url>/signup/gitlab/complete\". </li><li>Then use \"Secret\" and \"Id\" fields from GitLab to complete the options below.</li><li>Complete the Endpoint URLs below. </li></ol>", - "admin.gitlab.clientIdTitle": "Id:", - "admin.gitlab.clientIdDescription": "Obtain this value via the instructions above for logging into GitLab", - "admin.gitlab.clientSecretTitle": "Secret:", - "admin.gitab.clientSecretDescription": "Obtain this value via the instructions above for logging into GitLab.", - "admin.gitlab.authTitle": "Auth Endpoint:", - "admin.gitlab.authDescription": "Enter https://<your-gitlab-url>/oauth/authorize (example https://example.com:3000/oauth/authorize). Make sure you use HTTP or HTTPS in your URL depending on your server configuration.", - "admin.gitlab.tokenTitle": "Token Endpoint:", + "admin.gitlab.save": "Save", + "admin.gitlab.saving": "Saving Config...", + "admin.gitlab.settingsTitle": "GitLab Settings", "admin.gitlab.tokenDescription": "Enter https://<your-gitlab-url>/oauth/token. Make sure you use HTTP or HTTPS in your URL depending on your server configuration.", - "admin.gitlab.userTitle": "User API Endpoint:", + "admin.gitlab.tokenExample": "Ex \"\"", + "admin.gitlab.tokenTitle": "Token Endpoint:", + "admin.gitlab.true": "true", "admin.gitlab.userDescription": "Enter https://<your-gitlab-url>/api/v3/user. Make sure you use HTTP or HTTPS in your URL depending on your server configuration.", - "admin.gitlab.save": "Save", - "admin.image.storeLocal": "Local File System", - "admin.image.storeAmazonS3": "Amazon S3", - "admin.image.localExample": "Ex \"./data/\"", - "admin.image.amazonS3IdExample": "Ex \"AKIADTOVBGERKLCBV\"", - "admin.image.amazonS3SecretExample": "Ex \"jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY\"", + "admin.gitlab.userExample": "Ex \"\"", + "admin.gitlab.userTitle": "User API Endpoint:", + "admin.image.amazonS3BucketDescription": "Name you selected for your S3 bucket in AWS.", "admin.image.amazonS3BucketExample": "Ex \"mattermost-media\"", + "admin.image.amazonS3BucketTitle": "Amazon S3 Bucket:", + "admin.image.amazonS3IdDescription": "Obtain this credential from your Amazon EC2 administrator.", + "admin.image.amazonS3IdExample": "Ex \"AKIADTOVBGERKLCBV\"", + "admin.image.amazonS3IdTitle": "Amazon S3 Access Key Id:", + "admin.image.amazonS3RegionDescription": "AWS region you selected for creating your S3 bucket.", "admin.image.amazonS3RegionExample": "Ex \"us-east-1\"", - "admin.image.thumbWidthExample": "Ex \"120\"", - "admin.image.thumbHeightExample": "Ex \"100\"", - "admin.image.previewWidthExample": "Ex \"1024\"", - "admin.image.previewHeightExample": "Ex \"0\"", - "admin.image.profileWidthExample": "Ex \"1024\"", - "admin.image.profileHeightExample": "Ex \"0\"", - "admin.image.publicLinkExample": "Ex \"gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6\"", - "admin.image.saving": "Saving Config...", + "admin.image.amazonS3RegionTitle": "Amazon S3 Region:", + "admin.image.amazonS3SecretDescription": "Obtain this credential from your Amazon EC2 administrator.", + "admin.image.amazonS3SecretExample": "Ex \"jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY\"", + "admin.image.amazonS3SecretTitle": "Amazon S3 Secret Access Key:", + "admin.image.false": "false", "admin.image.fileSettings": "File Settings", - "admin.image.storeTitle": "Store Files In:", - "admin.image.localTitle": "Local Directory Location:", "admin.image.localDescription": "Directory to which image files are written. If blank, will be set to ./data/.", - "admin.image.amazonS3IdTitle": "Amazon S3 Access Key Id:", - "admin.image.amazonS3IdDescription": "Obtain this credential from your Amazon EC2 administrator.", - "admin.image.amazonS3SecretTitle": "Amazon S3 Secret Access Key:", - "admin.image.amazonS3SecretDescription": "Obtain this credential from your Amazon EC2 administrator.", - "admin.image.amazonS3BucketTitle": "Amazon S3 Bucket:", - "admin.image.amazonS3BucketDescription": "Name you selected for your S3 bucket in AWS.", - "admin.image.amazonS3RegionTitle": "Amazon S3 Region:", - "admin.image.amazonS3RegionDescription": "AWS region you selected for creating your S3 bucket.", - "admin.image.thumbWidthTitle": "Thumbnail Width:", - "admin.image.thumbWidthDescription": "Width of thumbnails generated from uploaded images. Updating this value changes how thumbnail images render in future, but does not change images created in the past.", - "admin.image.thumbHeightTitle": "Thumbnail Height:", - "admin.image.thumbHeightDescription": "Height of thumbnails generated from uploaded images. Updating this value changes how thumbnail images render in future, but does not change images created in the past.", - "admin.image.previewWidthTitle": "Preview Width:", - "admin.image.previewWidthDescription": "Maximum width of preview image. Updating this value changes how preview images render in future, but does not change images created in the past.", - "admin.image.previewHeightTitle": "Preview Height:", + "admin.image.localExample": "Ex \"./data/\"", + "admin.image.localTitle": "Local Directory Location:", "admin.image.previewHeightDescription": "Maximum height of preview image (\"0\": Sets to auto-size). Updating this value changes how preview images render in future, but does not change images created in the past.", - "admin.image.profileWidthTitle": "Profile Width:", - "admin.image.profileWidthDescription": "Width of profile picture.", - "admin.image.profileHeightTitle": "Profile Height:", + "admin.image.previewHeightExample": "Ex \"0\"", + "admin.image.previewHeightTitle": "Preview Height:", + "admin.image.previewWidthDescription": "Maximum width of preview image. Updating this value changes how preview images render in future, but does not change images created in the past.", + "admin.image.previewWidthExample": "Ex \"1024\"", + "admin.image.previewWidthTitle": "Preview Width:", "admin.image.profileHeightDescription": "Height of profile picture.", - "admin.image.shareTitle": "Share Public File Link: ", - "admin.image.true": "true", - "admin.image.false": "false", - "admin.image.shareDescription": "Allow users to share public links to files and images.", - "admin.image.publicLinkTitle": "Public Link Salt:", + "admin.image.profileHeightExample": "Ex \"0\"", + "admin.image.profileHeightTitle": "Profile Height:", + "admin.image.profileWidthDescription": "Width of profile picture.", + "admin.image.profileWidthExample": "Ex \"1024\"", + "admin.image.profileWidthTitle": "Profile Width:", "admin.image.publicLinkDescription": "32-character salt added to signing of public image links. Randomly generated on install. Click \"Re-Generate\" to create new salt.", + "admin.image.publicLinkExample": "Ex \"gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6\"", + "admin.image.publicLinkTitle": "Public Link Salt:", "admin.image.regenerate": "Re-Generate", "admin.image.save": "Save", - "admin.ldap.serverEx": "Ex \"10.0.0.23\"", - "admin.ldap.portEx": "Ex \"389\"", + "admin.image.saving": "Saving Config...", + "admin.image.shareDescription": "Allow users to share public links to files and images.", + "admin.image.shareTitle": "Share Public File Link: ", + "admin.image.storeAmazonS3": "Amazon S3", + "admin.image.storeLocal": "Local File System", + "admin.image.storeTitle": "Store Files In:", + "admin.image.thumbHeightDescription": "Height of thumbnails generated from uploaded images. Updating this value changes how thumbnail images render in future, but does not change images created in the past.", + "admin.image.thumbHeightExample": "Ex \"100\"", + "admin.image.thumbHeightTitle": "Thumbnail Height:", + "admin.image.thumbWidthDescription": "Width of thumbnails generated from uploaded images. Updating this value changes how thumbnail images render in future, but does not change images created in the past.", + "admin.image.thumbWidthExample": "Ex \"120\"", + "admin.image.thumbWidthTitle": "Thumbnail Width:", + "admin.image.true": "true", + "admin.ldap.bannerDesc": "If a user attribute changes on the LDAP server it will be updated the next time the user enters their credentials to log in to Mattermost. This includes if a user is made inactive or removed from an LDAP server. Synchronization with LDAP servers is planned in a future release.", + "admin.ldap.bannerHeading": "Note:", + "admin.ldap.baseDesc": "The Base DN is the Distinguished Name of the location where Mattermost should start its search for users in the LDAP tree.", "admin.ldap.baseEx": "Ex \"dc=mydomain,dc=com\"", - "admin.ldap.firstnameAttrEx": "Ex \"givenName\"", - "admin.ldap.lastnameAttrEx": "Ex \"sn\"", + "admin.ldap.baseTitle": "BaseDN:", + "admin.ldap.bindPwdDesc": "Password of the user given in \"Bind Username\".", + "admin.ldap.bindPwdTitle": "Bind Password:", + "admin.ldap.bindUserDesc": "The username used to perform the LDAP search. This should typically be an account created specifically for use with Mattermost. It should have access limited to read the portion of the LDAP tree specified in the BaseDN field.", + "admin.ldap.bindUserTitle": "Bind Username:", + "admin.ldap.emailAttrDesc": "The attribute in the LDAP server that will be used to populate the email addresses of users in Mattermost.", "admin.ldap.emailAttrEx": "Ex \"mail\"", - "admin.ldap.usernameAttrEx": "Ex \"sAMAccountName\"", - "admin.ldap.idAttrEx": "Ex \"sAMAccountName\"", - "admin.ldap.queryEx": "Ex \"60\"", - "admin.ldap.saving": "Saving Config...", - "admin.ldap.bannerHeading": "Note:", - "admin.ldap.bannerDesc": "If a user attribute changes on the LDAP server it will be updated the next time the user enters their credentials to log in to Mattermost. This includes if a user is made inactive or removed from an LDAP server. Synchronization with LDAP servers is planned in a future release.", - "admin.ldap.noLicense": "<h4 class=\"banner__heading\">Note:</h4><p>LDAP is an enterprise feature. Your current license does not support LDAP. Click <a href=\"http://mattermost.com\"target=\"_blank\">here</a> for information and pricing on enterprise licenses.</p>", - "admin.ldap.title": "LDAP Settings", + "admin.ldap.emailAttrTitle": "Email Attribute:", + "admin.ldap.enableDesc": "When true, Mattermost allows login using LDAP", "admin.ldap.enableTitle": "Enable Login With LDAP:", - "admin.ldap.true": "true", "admin.ldap.false": "false", - "admin.ldap.enableDesc": "When true, Mattermost allows login using LDAP", - "admin.ldap.serverTitle": "LDAP Server:", - "admin.ldap.serverDesc": "The domain or IP address of LDAP server.", - "admin.ldap.portTitle": "LDAP Port:", - "admin.ldap.portDesc": "The port Mattermost will use to connect to the LDAP server. Default is 389.", - "admin.ldap.baseTitle": "BaseDN:", - "admin.ldap.baseDesc": "The Base DN is the Distinguished Name of the location where Mattermost should start its search for users in the LDAP tree.", - "admin.ldap.bindUserTitle": "Bind Username:", - "admin.ldap.bindUserDesc": "The username used to perform the LDAP search. This should typically be an account created specifically for use with Mattermost. It should have access limited to read the portion of the LDAP tree specified in the BaseDN field.", - "admin.ldap.bindPwdTitle": "Bind Password:", - "admin.ldap.bindPwdDesc": "Password of the user given in \"Bind Username\".", - "admin.ldap.firstnameAttrTitle": "First Name Attrubute", "admin.ldap.firstnameAttrDesc": "The attribute in the LDAP server that will be used to populate the first name of users in Mattermost.", - "admin.ldap.lastnameAttrTitle": "Last Name Attribute:", - "admin.ldap.lastnameAttrDesc": "The attribute in the LDAP server that will be used to populate the last name of users in Mattermost.", - "admin.ldap.emailAttrTitle": "Email Attribute:", - "admin.ldap.emailAttrDesc": "The attribute in the LDAP server that will be used to populate the email addresses of users in Mattermost.", - "admin.ldap.usernameAttrTitle": "Username Attribute:", - "admin.ldap.uernameAttrDesc": "The attribute in the LDAP server that will be used to populate the username field in Mattermost. This may be the same as the ID Attribute.", - "admin.ldap.idAttrTitle": "Id Attribute: ", + "admin.ldap.firstnameAttrEx": "Ex \"givenName\"", + "admin.ldap.firstnameAttrTitle": "First Name Attrubute", "admin.ldap.idAttrDesc": "The attribute in the LDAP server that will be used as a unique identifier in Mattermost. It should be an LDAP attribute with a value that does not change, such as username or uid. If a user’s Id Attribute changes, it will create a new Mattermost account unassociated with their old one. This is the value used to log in to Mattermost in the \"LDAP Username\" field on the sign in page. Normally this attribute is the same as the “Username Attribute” field above. If your team typically uses domain\\\\username to sign in to other services with LDAP, you may choose to put domain\\\\username in this field to maintain consistency between sites.", - "admin.ldap.queryTitle": "Query Timeout (seconds):", + "admin.ldap.idAttrEx": "Ex \"sAMAccountName\"", + "admin.ldap.idAttrTitle": "Id Attribute: ", + "admin.ldap.lastnameAttrDesc": "The attribute in the LDAP server that will be used to populate the last name of users in Mattermost.", + "admin.ldap.lastnameAttrEx": "Ex \"sn\"", + "admin.ldap.lastnameAttrTitle": "Last Name Attribute:", + "admin.ldap.noLicense": "<h4 class=\"banner__heading\">Note:</h4><p>LDAP is an enterprise feature. Your current license does not support LDAP. Click <a href=\"http://mattermost.com\" target=\"_blank\">here</a> for information and pricing on enterprise licenses.</p>", + "admin.ldap.portDesc": "The port Mattermost will use to connect to the LDAP server. Default is 389.", + "admin.ldap.portEx": "Ex \"389\"", + "admin.ldap.portTitle": "LDAP Port:", "admin.ldap.queryDesc": "The timeout value for queries to the LDAP server. Increase if you are getting timeout errors caused by a slow LDAP server.", + "admin.ldap.queryEx": "Ex \"60\"", + "admin.ldap.queryTitle": "Query Timeout (seconds):", "admin.ldap.save": "Save", - "admin.support.saving": "Saving Config...", - "admin.support.title": "Legal and Support Settings", - "admin.support.termsTitle": "Terms of Service link:", - "admin.support.termsDesc": "Link to Terms of Service available to users on desktop and on mobile. Leaving this blank will hide the option to display a notice.", - "admin.support.privacyTitle": "Privacy Policy link:", - "admin.support.privacyDesc": "Link to Privacy Policy available to users on desktop and on mobile. Leaving this blank will hide the option to display a notice.", - "admin.support.aboutTitle": "About link:", - "admin.support.aboutDesc": "Link to About page for more information on your Mattermost deployment, for example its purpose and audience within your organization. Defaults to Mattermost information page.", - "admin.support.helpTitle": "Help link:", - "admin.support.helpDesc": "Link to help documentation from team site main menu. Typically not changed unless your organization chooses to create custom documentation.", - "admin.support.problemTitle": "Report a Problem link:", - "admin.support.problemDesc": "Link to help documentation from team site main menu. By default this points to the peer-to-peer troubleshooting forum where users can search for, find and request help with technical issues.", - "admin.support.emailTitle": "Support email:", - "admin.support.emailHelp": "Email shown during tutorial for end users to ask support questions.", - "admin.support.save": "Save", - "admin.license.removing": "Removing License...", - "admin.license.uploading": "Uploading License...", + "admin.ldap.saving": "Saving Config...", + "admin.ldap.serverDesc": "The domain or IP address of LDAP server.", + "admin.ldap.serverEx": "Ex \"10.0.0.23\"", + "admin.ldap.serverTitle": "LDAP Server:", + "admin.ldap.title": "LDAP Settings", + "admin.ldap.true": "true", + "admin.ldap.uernameAttrDesc": "The attribute in the LDAP server that will be used to populate the username field in Mattermost. This may be the same as the ID Attribute.", + "admin.ldap.usernameAttrEx": "Ex \"sAMAccountName\"", + "admin.ldap.usernameAttrTitle": "Username Attribute:", + "admin.licence.keyMigration": "If you’re migrating servers you may need to remove your license key from this server in order to install it on a new server. To start,<a href=\"http://mattermost.com\" target=\"_blank\">disable all Enterprise Edition features on this server</a>.This will enable the ability to remove the license key and downgrade this server from Enterprise Edition to Team Edition.", + "admin.license.edition": "Edition: ", "admin.license.enterpriseEdition": "Mattermost Enterprise Edition. Designed for enterprise-scale communication.", "admin.license.enterpriseType": "<div><p>This compiled release of Mattermost platform is provided under a <a href=\"http://mattermost.com\" target=\"_blank\">commercial license</a>from Mattermost, Inc. based on your subscription level and is subject to the <a href=\"{terms}\" target=\"_blank\">Terms of Service.</a></p><p>Your subscription details are as follows:</p>Name: {name}<br />Company or organization name: {company}<br/>Number of users: {users}<br/>License issued: {issued}<br/>Start date of license: {start}<br/>Expiry date of license: {expires}<br/>LDAP: {ldap}<br/></div>", + "admin.license.key": "License Key: ", "admin.license.keyRemove": "Remove Enterprise License and Downgrade Server", - "admin.licence.keyMigration": "If you’re migrating servers you may need to remove your license key from this server in order to install it on a new server. To start,<a href=\"http://mattermost.com\" target=\"_blank\">disable all Enterprise Edition features on this server</a>.This will enable the ability to remove the license key and downgrade this server from Enterprise Edition to Team Edition.", + "admin.license.removing": "Removing License...", "admin.license.teamEdition": "Mattermost Team Edition. Designed for teams from 5 to 50 users.", "admin.license.teamType": "<span><p>This compiled release of Mattermost platform is offered under an MIT license.</p><p>See MIT-COMPILED-LICENSE.txt in your root install directory for details. See NOTICES.txt for information about open source software used in this system.</p></span>", - "admin.license.upload": "Upload", - "admin.license.uploadDesc": "Upload a license key for Mattermost Enterprise Edition to upgrade this server. <a href=\"http://mattermost.com\" target=\"_blank\">Visit us online</a>to learn more about the benefits of Enterprise Edition or to purchase a key.", "admin.license.title": "Edition and License", - "admin.license.edition": "Edition: ", "admin.license.type": "License: ", - "admin.license.key": "License Key: ", - "admin.log.locationPlaceholder": "Enter your file location", - "admin.log.formatPlaceholder": "Enter your file format", - "admin.log.saving": "Saving Config...", - "admin.log.logSettings": "Log Settings", + "admin.license.upload": "Upload", + "admin.license.uploadDesc": "Upload a license key for Mattermost Enterprise Edition to upgrade this server. <a href=\"http://mattermost.com\" target=\"_blank\">Visit us online</a> to learn more about the benefits of Enterprise Edition or to purchase a key.", + "admin.license.uploading": "Uploading License...", + "admin.log.consoleDescription": "Typically set to false in production. Developers may set this field to true to output log messages to console based on the console level option. If true, server writes messages to the standard output stream (stdout).", "admin.log.consoleTitle": "Log To The Console: ", - "admin.log.true": "true", "admin.log.false": "false", - "admin.log.consoleDescription": "Typically set to false in production. Developers may set this field to true to output log messages to console based on the console level option. If true, server writes messages to the standard output stream (stdout).", - "admin.log.levelTitle": "Console Log Level:", - "admin.log.levelDescription": "This setting determines the level of detail at which log events are written to the console. ERROR: Outputs only error messages. INFO: Outputs error messages and information around startup and initialization. DEBUG: Prints high detail for developers working on debugging issues.", - "admin.log.fileTitle": "Log To File: ", "admin.log.fileDescription": "Typically set to true in production. When true, log files are written to the log file specified in file location field below.", - "admin.log.fileLevelTitle": "File Log Level:", "admin.log.fileLevelDescription": "This setting determines the level of detail at which log events are written to the log file. ERROR: Outputs only error messages. INFO: Outputs error messages and information around startup and initialization. DEBUG: Prints high detail for developers working on debugging issues.", - "admin.log.locationTitle": "File Location:", - "admin.log.locationDescription": "File to which log files are written. If blank, will be set to ./logs/mattermost, which writes logs to mattermost.log. Log rotation is enabled and every 10,000 lines of log information is written to new files stored in the same directory, for example mattermost.2015-09-23.001, mattermost.2015-09-23.002, and so forth.", - "admin.log.formatTitle": "File Format:", - "admin.log.formatDescription": "Format of log message output. If blank will be set to \"[%D %T] [%L] %M\", where:", - "admin.log.formatTime": "Time (15:04:05 MST)", + "admin.log.fileLevelTitle": "File Log Level:", + "admin.log.fileTitle": "Log To File: ", "admin.log.formatDateLong": "Date (2006/01/02)", "admin.log.formatDateShort": "Date (01/02/06)", + "admin.log.formatDescription": "Format of log message output. If blank will be set to \"[%D %T] [%L] %M\", where:", "admin.log.formatLevel": "Level (DEBG, INFO, EROR)", - "admin.log.formatSource": "Source", "admin.log.formatMessage": "Message", + "admin.log.formatPlaceholder": "Enter your file format", + "admin.log.formatSource": "Source", + "admin.log.formatTime": "Time (15:04:05 MST)", + "admin.log.formatTitle": "File Format:", + "admin.log.levelDescription": "This setting determines the level of detail at which log events are written to the console. ERROR: Outputs only error messages. INFO: Outputs error messages and information around startup and initialization. DEBUG: Prints high detail for developers working on debugging issues.", + "admin.log.levelTitle": "Console Log Level:", + "admin.log.locationDescription": "File to which log files are written. If blank, will be set to ./logs/mattermost, which writes logs to mattermost.log. Log rotation is enabled and every 10,000 lines of log information is written to new files stored in the same directory, for example mattermost.2015-09-23.001, mattermost.2015-09-23.002, and so forth.", + "admin.log.locationPlaceholder": "Enter your file location", + "admin.log.locationTitle": "File Location:", + "admin.log.logSettings": "Log Settings", "admin.log.save": "Save", - "admin.logs.title": "Server Logs", + "admin.log.saving": "Saving Config...", + "admin.log.true": "true", "admin.logs.reload": "Reload", - "admin.privacy.saving": "Saving Config...", - "admin.privacy.title": "Privacy Settings", - "admin.privacy.showEmailTitle": "Show Email Address: ", - "admin.privacy.true": "true", + "admin.logs.title": "Server Logs", + "admin.nav.help": "Help", + "admin.nav.logout": "Logout", + "admin.nav.report": "Report a Problem", + "admin.nav.switch": "Switch to {display_name}", "admin.privacy.false": "false", + "admin.privacy.save": "Save", + "admin.privacy.saving": "Saving Config...", "admin.privacy.showEmailDescription": "When false, hides email address of users from other users in the user interface, including team owners and team administrators. Used when system is set up for managing teams where some users choose to keep their contact information private.", - "admin.privacy.showFullNameTitle": "Show Full Name: ", + "admin.privacy.showEmailTitle": "Show Email Address: ", "admin.privacy.showFullNameDescription": "When false, hides full name of users from other users, including team owners and team administrators. Username is shown in place of full name.", - "admin.privacy.save": "Save", - "admin.rate.queriesExample": "Ex \"10\"", - "admin.rate.memoryExample": "Ex \"10000\"", - "admin.rate.httpHeaderExample": "Ex \"X-Real-IP\", \"X-Forwarded-For\"", - "admin.rate.saving": "Saving Config...", - "admin.rate.noteTitle": "Note:", - "admin.rate.noteDescription": "Changing properties in this section will require a server restart before taking effect.", - "admin.rate.title": "Rate Limit Settings", + "admin.privacy.showFullNameTitle": "Show Full Name: ", + "admin.privacy.title": "Privacy Settings", + "admin.privacy.true": "true", + "admin.rate.enableLimiterDescription": "When true, APIs are throttled at rates specified below.", "admin.rate.enableLimiterTitle": "Enable Rate Limiter: ", - "admin.rate.true": "true", "admin.rate.false": "false", - "admin.rate.enableLimiterDescription": "When true, APIs are throttled at rates specified below.", - "admin.rate.queriesTitle": "Number Of Queries Per Second:", - "admin.rate.queriesDescription": "Throttles API at this number of requests per second.", - "admin.rate.memoryTitle": "Memory Store Size:", + "admin.rate.httpHeaderDescription": "When filled in, vary rate limiting by HTTP header field specified (e.g. when configuring NGINX set to \"X-Real-IP\", when configuring AmazonELB set to \"X-Forwarded-For\").", + "admin.rate.httpHeaderExample": "Ex \"X-Real-IP\", \"X-Forwarded-For\"", + "admin.rate.httpHeaderTitle": "Vary By HTTP Header:", "admin.rate.memoryDescription": "Maximum number of users sessions connected to the system as determined by \"Vary By Remote Address\" and \"Vary By Header\" settings below.", - "admin.rate.remoteTitle": "Vary By Remote Address: ", + "admin.rate.memoryExample": "Ex \"10000\"", + "admin.rate.memoryTitle": "Memory Store Size:", + "admin.rate.noteDescription": "Changing properties in this section will require a server restart before taking effect.", + "admin.rate.noteTitle": "Note:", + "admin.rate.queriesDescription": "Throttles API at this number of requests per second.", + "admin.rate.queriesExample": "Ex \"10\"", + "admin.rate.queriesTitle": "Number Of Queries Per Second:", "admin.rate.remoteDescription": "When true, rate limit API access by IP address.", - "admin.rate.httpHeaderTitle": "Vary By HTTP Header:", - "admin.rate.httpHeaderDescription": "When filled in, vary rate limiting by HTTP header field specified (e.g. when configuring NGINX set to \"X-Real-IP\", when configuring AmazonELB set to \"X-Forwarded-For\").", + "admin.rate.remoteTitle": "Vary By Remote Address: ", "admin.rate.save": "Save", - "admin.reset_password.submit": "Please enter at least {chars} characters.", - "admin.reset_password.title": "Reset Password", - "admin.reset_password.newPassword": "New Password", + "admin.rate.saving": "Saving Config...", + "admin.rate.title": "Rate Limit Settings", + "admin.rate.true": "true", "admin.reset_password.close": "Close", + "admin.reset_password.newPassword": "New Password", "admin.reset_password.select": "Select", - "admin.select_team.selectTeam": "Select Team", + "admin.reset_password.submit": "Please enter at least {chars} characters.", + "admin.reset_password.title": "Reset Password", "admin.select_team.close": "Close", "admin.select_team.select": "Select", - "admin.service.listenExample": "Ex \":8065\"", + "admin.select_team.selectTeam": "Select Team", + "admin.service.attemptDescription": "Login attempts allowed before user is locked out and required to reset password via email.", "admin.service.attemptExample": "Ex \"10\"", - "admin.service.segmentExample": "Ex \"g3fgGOXJAQ43QV7rAh6iwQCkV4cA1Gs\"", - "admin.service.googleExample": "Ex \"7rAh6iwQCkV4cA1Gsg3fgGOXJAQ43QV\"", - "admin.service.sessionDaysEx": "Ex \"30\"", - "admin.service.saving": "Saving Config...", - "admin.service.title": "Service Settings", - "admin.service.listenAddress": "Listen Address:", - "admin.service.listenDescription": "The address to which to bind and listen. Entering \":8065\" will bind to all interfaces or you can choose one like \"127.0.0.1:8065\". Changing this will require a server restart before taking effect.", "admin.service.attemptTitle": "Maximum Login Attempts:", - "admin.service.attemptDescription": "Login attempts allowed before user is locked out and required to reset password via email.", - "admin.service.segmentTitle": "Segment Developer Key:", - "admin.service.segmentDescription": "For users running a SaaS services, sign up for a key at Segment.com to track metrics.", - "admin.service.googleTitle": "Google Developer Key:", - "admin.service.googleDescription": "Set this key to enable embedding of YouTube video previews based on hyperlinks appearing in messages or comments. Instructions to obtain a key available at<a href=\"https://www.youtube.com/watch?v=Im69kzhpR3I\" target=\"_blank\">https://www.youtube.com/watch?v=Im69kzhpR3I</a>.Leaving the field blank disables the automatic generation of YouTube video previews from links.", - "admin.service.webhooksTitle": "Enable Incoming Webhooks: ", - "admin.service.true": "true", - "admin.service.false": "false", - "admin.service.webhooksDescription": "When true, incoming webhooks will be allowed. To help combat phishing attacks, all posts from webhooks will be labelled by a BOT tag.", - "admin.service.outWebhooksTitle": "Enable Outgoing Webhooks: ", - "admin.service.outWebhooksDesc": "When true, outgoing webhooks will be allowed.", - "admin.service.cmdsTitle": "Enable Slash Commands: ", "admin.service.cmdsDesc": "When true, user created slash commands will be allowed.", - "admin.service.integrationAdmin": "Enable Integrations for Admin Only: ", - "admin.service.integrationAdminDesc": "When true, user created integrations can only be created by admins.", - "admin.service.overrideTitle": "Enable Overriding Usernames from Webhooks and Slash Commands: ", - "admin.service.overrideDescription": "When true, webhooks and slash commands will be allowed to change the username they are posting as. Note, combined with allowing icon overriding, this could open users up to phishing attacks.", - "admin.service.iconTitle": "Enable Overriding Icon from Webhooks and Slash Commands: ", - "admin.service.iconDescription": "When true, webhooks and slash commands will be allowed to change the icon they post with. Note, combined with allowing username overriding, this could open users up to phishing attacks.", - "admin.service.testingTitle": "Enable Testing: ", - "admin.service.testingDescription": "(Developer Option) When true, /loadtest slash command is enabled to load test accounts and test data. Changing this will require a server restart before taking effect.", - "admin.service.developerTitle": "Enable Developer Mode: ", + "admin.service.cmdsTitle": "Enable Slash Commands: ", "admin.service.developerDesc": "(Developer Option) When true, extra information around errors will be displayed in the UI.", - "admin.service.securityTitle": "Enable Security Alerts: ", - "admin.service.securityDesc": "When true, System Administrators are notified by email if a relevant security fix alert has been announced in the last 12 hours. Requires email to be enabled.", - "admin.service.insecureTlsTitle": "Enable Insecure Outgoing Connections: ", + "admin.service.developerTitle": "Enable Developer Mode: ", + "admin.service.false": "false", + "admin.service.googleDescription": "Set this key to enable embedding of YouTube video previews based on hyperlinks appearing in messages or comments. Instructions to obtain a key available at <a href=\"https://www.youtube.com/watch?v=Im69kzhpR3I\" target=\"_blank\">https://www.youtube.com/watch?v=Im69kzhpR3I</a>. Leaving the field blank disables the automatic generation of YouTube video previews from links.", + "admin.service.googleExample": "Ex \"7rAh6iwQCkV4cA1Gsg3fgGOXJAQ43QV\"", + "admin.service.googleTitle": "Google Developer Key:", + "admin.service.iconDescription": "When true, webhooks and slash commands will be allowed to change the icon they post with. Note, combined with allowing username overriding, this could open users up to phishing attacks.", + "admin.service.iconTitle": "Enable Overriding Icon from Webhooks and Slash Commands: ", "admin.service.insecureTlsDesc": "When true, any outgoing HTTPS requests will accept unverified, self-signed certificates. For example, outgoing webhooks to a server with a self-signed TLS certificate, using any domain, will be allowed. Note that this makes these connections susceptible to man-in-the-middle attacks.", - "admin.service.webSessionDays": "Session Length for Web in Days:", - "admin.service.webSessionDaysDesc": "The web session will expire after the number of days specified and will require a user to login again.", + "admin.service.insecureTlsTitle": "Enable Insecure Outgoing Connections: ", + "admin.service.integrationAdmin": "Enable Integrations for Admin Only: ", + "admin.service.integrationAdminDesc": "When true, user created integrations can only be created by admins.", + "admin.service.listenAddress": "Listen Address:", + "admin.service.listenDescription": "The address to which to bind and listen. Entering \":8065\" will bind to all interfaces or you can choose one like \"127.0.0.1:8065\". Changing this will require a server restart before taking effect.", + "admin.service.listenExample": "Ex \":8065\"", "admin.service.mobileSessionDays": "Session Length for Mobile Device in Days:", "admin.service.mobileSessionDaysDesc": "The native mobile session will expire after the number of days specified and will require a user to login again.", - "admin.service.ssoSessionDays": "Session Length for SSO in Days:", - "admin.service.ssoSessionDaysDesc": "The SSO session will expire after the number of days specified and will require a user to login again.", + "admin.service.outWebhooksDesc": "When true, outgoing webhooks will be allowed.", + "admin.service.outWebhooksTitle": "Enable Outgoing Webhooks: ", + "admin.service.overrideDescription": "When true, webhooks and slash commands will be allowed to change the username they are posting as. Note, combined with allowing icon overriding, this could open users up to phishing attacks.", + "admin.service.overrideTitle": "Enable Overriding Usernames from Webhooks and Slash Commands: ", + "admin.service.save": "Save", + "admin.service.saving": "Saving Config...", + "admin.service.securityDesc": "When true, System Administrators are notified by email if a relevant security fix alert has been announced in the last 12 hours. Requires email to be enabled.", + "admin.service.securityTitle": "Enable Security Alerts: ", + "admin.service.segmentDescription": "For users running a SaaS services, sign up for a key at Segment.com to track metrics.", + "admin.service.segmentExample": "Ex \"g3fgGOXJAQ43QV7rAh6iwQCkV4cA1Gs\"", + "admin.service.segmentTitle": "Segment Developer Key:", "admin.service.sessionCache": "Session Cache in Minutes:", "admin.service.sessionCacheDesc": "The number of minutes to cache a session in memory.", - "admin.service.save": "Save", - "admin.sql.warning": "Warning: re-generating this salt may cause some columns in the database to return empty results.", - "admin.sql.maxConnectionsExample": "Ex \"10\"", - "admin.sql.maxOpenExample": "Ex \"10\"", - "admin.sql.keyExample": "Ex \"gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6\"", - "admin.sql.saving": "Saving Config...", - "admin.sql.noteTitle": "Note:", - "admin.sql.noteDescription": "Changing properties in this section will require a server restart before taking effect.", - "admin.sql.title": "SQL Settings", - "admin.sql.driverName": "Driver Name:", + "admin.service.sessionDaysEx": "Ex \"30\"", + "admin.service.ssoSessionDays": "Session Length for SSO in Days:", + "admin.service.ssoSessionDaysDesc": "The SSO session will expire after the number of days specified and will require a user to login again.", + "admin.service.testingDescription": "(Developer Option) When true, /loadtest slash command is enabled to load test accounts and test data. Changing this will require a server restart before taking effect.", + "admin.service.testingTitle": "Enable Testing: ", + "admin.service.title": "Service Settings", + "admin.service.true": "true", + "admin.service.webSessionDays": "Session Length for Web in Days:", + "admin.service.webSessionDaysDesc": "The web session will expire after the number of days specified and will require a user to login again.", + "admin.service.webhooksDescription": "When true, incoming webhooks will be allowed. To help combat phishing attacks, all posts from webhooks will be labelled by a BOT tag.", + "admin.service.webhooksTitle": "Enable Incoming Webhooks: ", + "admin.sidebar.addTeamSidebar": "Add team from sidebar menu", + "admin.sidebar.audits": "Compliance and Auditing", + "admin.sidebar.email": "Email Settings", + "admin.sidebar.file": "File Settings", + "admin.sidebar.gitlab": "GitLab Settings", + "admin.sidebar.ldap": "LDAP Settings", + "admin.sidebar.license": "Edition and License", + "admin.sidebar.loading": "Loading", + "admin.sidebar.log": "Log Settings", + "admin.sidebar.logs": "Logs", + "admin.sidebar.other": "OTHER", + "admin.sidebar.privacy": "Privacy Settings", + "admin.sidebar.rate_limit": "Rate Limit Settings", + "admin.sidebar.reports": "SITE REPORTS", + "admin.sidebar.rmTeamSidebar": "Remove team from sidebar menu", + "admin.sidebar.service": "Service Settings", + "admin.sidebar.settings": "SETTINGS", + "admin.sidebar.sql": "SQL Settings", + "admin.sidebar.statistics": "- Statistics", + "admin.sidebar.support": "Legal and Support Settings", + "admin.sidebar.team": "Team Settings", + "admin.sidebar.teams": "TEAMS ({count})", + "admin.sidebar.users": "- Users", + "admin.sidebar.view_statistics": "View Statistics", + "admin.sidebarHeader.systemConsole": "System Console", "admin.sql.dataSource": "Data Source:", - "admin.sql.replicas": "Data Source Replicas:", - "admin.sql.maxConnectionsTitle": "Maximum Idle Connections:", + "admin.sql.driverName": "Driver Name:", + "admin.sql.false": "false", + "admin.sql.keyDescription": "32-character salt available to encrypt and decrypt sensitive fields in database.", + "admin.sql.keyExample": "Ex \"gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6\"", + "admin.sql.keyTitle": "At Rest Encrypt Key:", "admin.sql.maxConnectionsDescription": "Maximum number of idle connections held open to the database.", - "admin.sql.maxOpenTitle": "Maximum Open Connections:", + "admin.sql.maxConnectionsExample": "Ex \"10\"", + "admin.sql.maxConnectionsTitle": "Maximum Idle Connections:", "admin.sql.maxOpenDescription": "Maximum number of open connections held open to the database.", - "admin.sql.keyTitle": "At Rest Encrypt Key:", - "admin.sql.keyDescription": "32-character salt available to encrypt and decrypt sensitive fields in database.", + "admin.sql.maxOpenExample": "Ex \"10\"", + "admin.sql.maxOpenTitle": "Maximum Open Connections:", + "admin.sql.noteDescription": "Changing properties in this section will require a server restart before taking effect.", + "admin.sql.noteTitle": "Note:", "admin.sql.regenerate": "Re-Generate", + "admin.sql.replicas": "Data Source Replicas:", + "admin.sql.save": "Save", + "admin.sql.saving": "Saving Config...", + "admin.sql.title": "SQL Settings", + "admin.sql.traceDescription": "(Development Mode) When true, executing SQL statements are written to the log.", "admin.sql.traceTitle": "Trace: ", "admin.sql.true": "true", - "admin.sql.false": "false", - "admin.sql.traceDescription": "(Development Mode) When true, executing SQL statements are written to the log.", - "admin.sql.save": "Save", - "admin.system_analytics.totalPosts": "Total Posts", + "admin.sql.warning": "Warning: re-generating this salt may cause some columns in the database to return empty results.", + "admin.support.aboutDesc": "Link to About page for more information on your Mattermost deployment, for example its purpose and audience within your organization. Defaults to Mattermost information page.", + "admin.support.aboutTitle": "About link:", + "admin.support.emailHelp": "Email shown during tutorial for end users to ask support questions.", + "admin.support.emailTitle": "Support email:", + "admin.support.helpDesc": "Link to help documentation from team site main menu. Typically not changed unless your organization chooses to create custom documentation.", + "admin.support.helpTitle": "Help link:", + "admin.support.privacyDesc": "Link to Privacy Policy available to users on desktop and on mobile. Leaving this blank will hide the option to display a notice.", + "admin.support.privacyTitle": "Privacy Policy link:", + "admin.support.problemDesc": "Link to help documentation from team site main menu. By default this points to the peer-to-peer troubleshooting forum where users can search for, find and request help with technical issues.", + "admin.support.problemTitle": "Report a Problem link:", + "admin.support.save": "Save", + "admin.support.saving": "Saving Config...", + "admin.support.termsDesc": "Link to Terms of Service available to users on desktop and on mobile. Leaving this blank will hide the option to display a notice.", + "admin.support.termsTitle": "Terms of Service link:", + "admin.support.title": "Legal and Support Settings", "admin.system_analytics.activeUsers": "Active Users With Posts", "admin.system_analytics.title": "the System", - "admin.team_analytics.totalPosts": "Total Posts", - "admin.team_analytics.activeUsers": "Active Users With Posts", - "admin.team.siteNameExample": "Ex \"Mattermost\"", + "admin.system_analytics.totalPosts": "Total Posts", + "admin.team.dirDesc": "When true, teams that are configured to show in team directory will show on main page inplace of creating a new team.", + "admin.team.dirTitle": "Enable Team Directory: ", + "admin.team.false": "false", + "admin.team.maxUsersDescription": "Maximum total number of users per team, including both active and inactive users.", "admin.team.maxUsersExample": "Ex \"25\"", + "admin.team.maxUsersTitle": "Max Users Per Team:", + "admin.team.restrictDescription": "Teams and user accounts can only be created from a specific domain (e.g. \"mattermost.org\") or list of comma-separated domains (e.g. \"corp.mattermost.com, mattermost.org\").", "admin.team.restrictExample": "Ex \"corp.mattermost.com, mattermost.org\"", + "admin.team.restrictNameDesc": "When true, You cannot create a team name with reserved words like www, admin, support, test, channel, etc", + "admin.team.restrictNameTitle": "Restrict Team Names: ", + "admin.team.restrictTitle": "Restrict Creation To Domains:", + "admin.team.save": "Save", "admin.team.saving": "Saving Config...", - "admin.team.title": "Team Settings", - "admin.team.siteNameTitle": "Site Name:", "admin.team.siteNameDescription": "Name of service shown in login screens and UI.", - "admin.team.maxUsersTitle": "Max Users Per Team:", - "admin.team.maxUsersDescription": "Maximum total number of users per team, including both active and inactive users.", + "admin.team.siteNameExample": "Ex \"Mattermost\"", + "admin.team.siteNameTitle": "Site Name:", + "admin.team.teamCreationDescription": "When false, the ability to create teams is disabled. The create team button displays error when pressed.", "admin.team.teamCreationTitle": "Enable Team Creation: ", + "admin.team.title": "Team Settings", "admin.team.true": "true", - "admin.team.false": "false", - "admin.team.teamCreationDescription": "When false, the ability to create teams is disabled. The create team button displays error when pressed.", - "admin.team.userCreationTitle": "Enable User Creation: ", "admin.team.userCreationDescription": "When false, the ability to create accounts is disabled. The create account button displays error when pressed.", - "admin.team.restrictTitle": "Restrict Creation To Domains:", - "admin.team.restrictDescription": "Teams and user accounts can only be created from a specific domain (e.g. \"mattermost.org\") or list of comma-separated domains (e.g. \"corp.mattermost.com, mattermost.org\").", - "admin.team.restrictNameTitle": "Restrict Team Names: ", - "admin.team.restrictNameDesc": "When true, You cannot create a team name with reserved words like www, admin, support, test, channel, etc", - "admin.team.dirTitle": "Enable Team Directory: ", - "admin.team.dirDesc": "When true, teams that are configured to show in team directory will show on main page inplace of creating a new team.", - "admin.team.save": "Save", + "admin.team.userCreationTitle": "Enable User Creation: ", + "admin.team_analytics.activeUsers": "Active Users With Posts", + "admin.team_analytics.totalPosts": "Total Posts", "admin.userList.title": "Users for {team}", "admin.userList.title2": "Users for {team} ({count})", + "admin.user_item.confirmDemoteDescription": "If you demote yourself from the System Admin role and there is not another user with System Admin privileges, you'll need to re-assign a System Admin by accessing the Mattermost server through a terminal and running the following command.", "admin.user_item.confirmDemoteRoleTitle": "Confirm demotion from System Admin role", "admin.user_item.confirmDemotion": "Confirm Demotion", - "admin.user_item.confirmDemoteDescription": "If you demote yourself from the System Admin role and there is not another user with System Admin privileges, you'll need to re-assign a System Admin by accessing the Mattermost server through a terminal and running the following command.", "admin.user_item.confirmDemotionCmd": "platform -assign_role -team_name=\"yourteam\" -email=\"name@yourcompany.com\" -role=\"system_admin\"", - "admin.user_item.member": "Member", - "admin.user_item.sysAdmin": "System Admin", - "admin.user_item.teamAdmin": "Team Admin", "admin.user_item.inactive": "Inactive", - "admin.user_item.makeSysAdmin": "Make System Admin", - "admin.user_item.makeTeamAdmin": "Make Team Admin", - "admin.user_item.makeMember": "Make Member", "admin.user_item.makeActive": "Make Active", "admin.user_item.makeInactive": "Make Inactive", + "admin.user_item.makeMember": "Make Member", + "admin.user_item.makeSysAdmin": "Make System Admin", + "admin.user_item.makeTeamAdmin": "Make Team Admin", + "admin.user_item.member": "Member", "admin.user_item.resetPwd": "Reset Password", - "audit_table.sessionRevoked": "The session with id {sessionId} was revoked", - "audit_table.channelCreated": "Created the {channelName} channel/group", - "audit_table.establishedDM": "Established a direct message channel with {username}", - "audit_table.nameUpdated": "Updated the {channelName} channel/group name", - "audit_table.headerUpdated": "Updated the {channelName} channel/group header", - "audit_table.channelDeleted": "Deleted the channel/group with the URL {url}", - "audit_table.userAdded": "Added {username} to the {channelName} channel/group", - "audit_table.userRemoved": "Removed {username} to the {channelName} channel/group", - "audit_table.attemptedRegisterApp": "Attempted to register a new OAuth Application with ID {id}", + "admin.user_item.sysAdmin": "System Admin", + "admin.user_item.teamAdmin": "Team Admin", + "audit_table.accountActive": "Account made active", + "audit_table.accountInactive": "Account made inactive", + "audit_table.action": "Action", "audit_table.attemptedAllowOAuthAccess": "Attempted to allow a new OAuth service access", - "audit_table.successfullOAuthAccess": "Successfully gave a new OAuth service access", - "audit_table.failedOAuthAccess": "Failed to allow a new OAuth service access - the redirect URI did not match the previously registered callback", - "audit_table.attemptedOAuthToken": "Attempted to get an OAuth access token", - "audit_table.successfullOAuthToken": "Successfully added a new OAuth service", - "audit_table.oauthTokenFailed": "Failed to get an OAuth access token - {token}", + "audit_table.attemptedLicenseAdd": "Attempted to add new license", "audit_table.attemptedLogin": "Attempted to login", - "audit_table.successfullLogin": "Successfully logged in", - "audit_table.failedLogin": "FAILED login attempt", - "audit_table.updatePicture": "Updated your profile picture", - "audit_table.updateGeneral": "Updated the general settings of your account", + "audit_table.attemptedOAuthToken": "Attempted to get an OAuth access token", "audit_table.attemptedPassword": "Attempted to change password", - "audit_table.successfullPassword": "Successfully changed password", - "audit_table.failedPassword": "Failed to change password - tried to update user password who was logged in through oauth", - "audit_table.updatedRol": "Updated user role(s) to ", - "audit_table.member": "member", - "audit_table.accountActive": "Account made active", - "audit_table.accountInactive": "Account made inactive", - "audit_table.by": " by {username}", - "audit_table.byAdmin": " by an admin", - "audit_table.sentEmail": "Sent an email to {email} to reset your password", + "audit_table.attemptedRegisterApp": "Attempted to register a new OAuth Application with ID {id}", "audit_table.attemptedReset": "Attempted to reset password", - "audit_table.successfullReset": "Successfully reset password", - "audit_table.updateGlobalNotifications": "Updated your global notification settings", "audit_table.attemptedWebhookCreate": "Attempted to create a webhook", - "audit_table.successfullWebhookCreate": "Successfully created a webhook", - "audit_table.failedWebhookCreate": "Failed to create a webhook - bad channel permissions", "audit_table.attemptedWebhookDelete": "Attempted to delete a webhook", - "audit_table.successfullWebhookDelete": "Successfully deleted a webhook", - "audit_table.failedWebhookDelete": "Failed to delete a webhook - inappropriate conditions", - "audit_table.logout": "Logged out of your account", - "audit_table.verified": "Sucessfully verified your email address", - "audit_table.revokedAll": "Revoked all current sessions for the team", - "audit_table.loginAttempt": " (Login attempt)", - "audit_table.loginFailure": " (Login failure)", - "audit_table.attemptedLicenseAdd": "Attempted to add new license", - "audit_table.successfullLicenseAdd": "Successfully added new license", + "audit_table.by": " by {username}", + "audit_table.byAdmin": " by an admin", + "audit_table.channelCreated": "Created the {channelName} channel/group", + "audit_table.channelDeleted": "Deleted the channel/group with the URL {url}", + "audit_table.establishedDM": "Established a direct message channel with {username}", "audit_table.failedExpiredLicenseAdd": "Failed to add a new license as it has either expired or not yet been started", "audit_table.failedInvalidLicenseAdd": "Failed to add an invalid license", - "audit_table.licenseRemoved": "Successfully removed a license", - "audit_table.userId": "User ID", + "audit_table.failedLogin": "FAILED login attempt", + "audit_table.failedOAuthAccess": "Failed to allow a new OAuth service access - the redirect URI did not match the previously registered callback", + "audit_table.failedPassword": "Failed to change password - tried to update user password who was logged in through oauth", + "audit_table.failedWebhookCreate": "Failed to create a webhook - bad channel permissions", + "audit_table.failedWebhookDelete": "Failed to delete a webhook - inappropriate conditions", + "audit_table.headerUpdated": "Updated the {channelName} channel/group header", "audit_table.ip": "IP Address", + "audit_table.licenseRemoved": "Successfully removed a license", + "audit_table.loginAttempt": " (Login attempt)", + "audit_table.loginFailure": " (Login failure)", + "audit_table.logout": "Logged out of your account", + "audit_table.member": "member", + "audit_table.nameUpdated": "Updated the {channelName} channel/group name", + "audit_table.oauthTokenFailed": "Failed to get an OAuth access token - {token}", + "audit_table.revokedAll": "Revoked all current sessions for the team", + "audit_table.sentEmail": "Sent an email to {email} to reset your password", "audit_table.session": "Session ID", + "audit_table.sessionRevoked": "The session with id {sessionId} was revoked", + "audit_table.successfullLicenseAdd": "Successfully added new license", + "audit_table.successfullLogin": "Successfully logged in", + "audit_table.successfullOAuthAccess": "Successfully gave a new OAuth service access", + "audit_table.successfullOAuthToken": "Successfully added a new OAuth service", + "audit_table.successfullPassword": "Successfully changed password", + "audit_table.successfullReset": "Successfully reset password", + "audit_table.successfullWebhookCreate": "Successfully created a webhook", + "audit_table.successfullWebhookDelete": "Successfully deleted a webhook", "audit_table.timestamp": "Timestamp", - "audit_table.action": "Action", - "authorize.title": "An application would like to connect to your {teamName} account", - "authorize.app": "The app <strong>{appName}</strong> would like the ability to access and modify your basic information.", + "audit_table.updateGeneral": "Updated the general settings of your account", + "audit_table.updateGlobalNotifications": "Updated your global notification settings", + "audit_table.updatePicture": "Updated your profile picture", + "audit_table.updatedRol": "Updated user role(s) to ", + "audit_table.userAdded": "Added {username} to the {channelName} channel/group", + "audit_table.userId": "User ID", + "audit_table.userRemoved": "Removed {username} to the {channelName} channel/group", + "audit_table.verified": "Sucessfully verified your email address", "authorize.access": "Allow <strong>{appName}</strong> access?", - "authorize.deny": "Deny", "authorize.allow": "Allow", + "authorize.app": "The app <strong>{appName}</strong> would like the ability to access and modify your basic information.", + "authorize.deny": "Deny", + "authorize.title": "An application would like to connect to your {teamName} account", "center_panel.recent": "Click here to jump to recent messages. ", - "change_url.longer": "Must be longer than two characters", - "change_url.startWithLetter": "Must start with a letter or number", + "chanel_header.addMembers": "Add Members", + "change_url.close": "Close", "change_url.endWithLetter": "Must end with a letter or number", - "change_url.noUnderscore": "Can not contain two underscores in a row.", "change_url.invalidUrl": "Invalid URL", - "change_url.close": "Close", - "channel_header.recentMentions": "Recent Mentions", + "change_url.longer": "Must be longer than two characters", + "change_url.noUnderscore": "Can not contain two underscores in a row.", + "change_url.startWithLetter": "Must start with a letter or number", + "channel_flow.alreadyExist": "A channel with that URL already exists", + "channel_flow.changeUrlDescription": "Some characters are not allowed in URLs and may be removed.", + "channel_flow.changeUrlTitle": "Change {term} URL", + "channel_flow.channel": "Channel", + "channel_flow.create": "Create {term}", + "channel_flow.group": "Group", + "channel_flow.invalidName": "Invalid Channel Name", + "channel_flow.set_url_title": "Set {term} URL", "channel_header.channel": "Channel", - "channel_header.group": "Group", "channel_header.channelHeader": "Set Channel Header...", - "channel_header.viewInfo": "View Info", - "chanel_header.addMembers": "Add Members", + "channel_header.delete": "Delete {term}...", + "channel_header.group": "Group", + "channel_header.leave": "Leave {term}", "channel_header.manageMembers": "Manage Members", - "channel_header.setHeader": "Set {term} Header...", - "channel_header.setPurpose": "Set {term} Purpose...", "channel_header.notificationPreferences": "Notification Preferences", + "channel_header.recentMentions": "Recent Mentions", "channel_header.rename": "Rename {term}...", - "channel_header.delete": "Delete {term}...", - "channel_header.leave": "Leave {term}", - "channel_info.notFound": "No Channel Found", - "channel_info.name": "Channel Name:", - "channel_info.url": "Channel URL:", + "channel_header.setHeader": "Set {term} Header...", + "channel_header.setPurpose": "Set {term} Purpose...", + "channel_header.viewInfo": "View Info", + "channel_info.close": "Close", "channel_info.id": "Channel ID:", + "channel_info.name": "Channel Name:", + "channel_info.notFound": "No Channel Found", "channel_info.purpose": "Channel Purpose:", - "channel_info.close": "Close", + "channel_info.url": "Channel URL:", "channel_invite.addNewMembers": "Add New Members to ", "channel_invite.close": "Close", + "channel_loader.posted": "Posted", "channel_loader.socketError": "Please check connection, Mattermost unreachable. If issue persists, ask administrator to check WebSocket port.", "channel_loader.someone": "Someone", - "channel_loader.posted": "Posted", - "channel_loader.uploadedImage": " uploaded an image", - "channel_loader.uploadedFile": " uploaded a file", "channel_loader.something": " did something new", + "channel_loader.uploadedFile": " uploaded a file", + "channel_loader.uploadedImage": " uploaded an image", "channel_loader.wrote": " wrote: ", - "channel_memebers_modal.members": " Members", "channel_members_modal.addNew": " Add New Members", "channel_members_modal.close": "Close", + "channel_memebers_modal.members": " Members", + "channel_modal.cancel": "Cancel", + "channel_modal.channel": "Channel", + "channel_modal.createNew": "Create New ", + "channel_modal.descriptionHelp": "Describe how this {term} should be used.", + "channel_modal.displayNameError": "This field is required", + "channel_modal.edit": "Edit", + "channel_modal.group": "Group", + "channel_modal.modalTitle": "New ", + "channel_modal.name": "Name", + "channel_modal.nameEx": "E.g.: \"Bugs\", \"Marketing\", \"办公室恋情\"", + "channel_modal.optional": "(optional)", + "channel_modal.privateGroup1": "Create a new private group with restricted membership. ", + "channel_modal.privateGroup2": "Create a private group", + "channel_modal.publicChannel1": "Create a public channel", + "channel_modal.publicChannel2": "Create a new public channel anyone can join. ", + "channel_modal.purpose": "Purpose", "channel_notifications.allActivity": "For all activity", - "channel_notifications.onlyMentions": "Only for mentions", + "channel_notifications.allUnread": "For all unread messages", + "channel_notifications.globalDefault": "Global default ({notifyLevel})", + "channel_notifications.markUnread": "Mark Channel Unread", "channel_notifications.never": "Never", - "channel_notifications.sendDesktop": "Send desktop notifications", - "channel_notifications.globalDefault": "Global default ({notifyLevel}", + "channel_notifications.onlyMentions": "Only for mentions", "channel_notifications.override": "Selecting an option other than \"Default\" will override the global notification settings. Desktop notifications are available on Firefox, Safari, and Chrome.", - "channel_notifications.markUnread": "Mark Channel Unread", - "channel_notifications.allUnread": "For all unread messages", - "channel_notifications.unreadInfo": "The channel name is bolded in the sidebar when there are unread messages. Selecting \"Only for mentions\" will bold the channel only when you are mentioned.", "channel_notifications.preferences": "Notification Preferences for ", + "channel_notifications.sendDesktop": "Send desktop notifications", + "channel_notifications.unreadInfo": "The channel name is bolded in the sidebar when there are unread messages. Selecting \"Only for mentions\" will bold the channel only when you are mentioned.", + "choose_auth_page.emailCreate": "Create new team with email address", + "choose_auth_page.find": "Find my teams", + "choose_auth_page.gitlabCreate": "Create new team with GitLab Account", + "choose_auth_page.googleCreate": "Create new team with Google Apps Account", + "choose_auth_page.noSignup": "No sign-up methods configured, please contact your system administrator.", "claim.account.noEmail": "No email specified", - "claim.email_to_sso.pwdError": "Please enter your password.", + "claim.email_to_sso.enterPwd": "Enter the password for your {team} {site} account", "claim.email_to_sso.pwd": "Password", - "claim.email_to_sso.title": "Switch Email/Password Account to {uiType}", - "claim.email_to_sso.ssoType": "Upon claiming your account, you will only be able to login with {type} SSO. You must already have a valid {type} account", + "claim.email_to_sso.pwdError": "Please enter your password.", "claim.email_to_sso.ssoNote": "You must already have a valid {type} account", - "claim.email_to_sso.enterPwd": "Enter the password for your {team} {site} account", + "claim.email_to_sso.ssoType": "Upon claiming your account, you will only be able to login with {type} SSO. You must already have a valid {type} account", "claim.email_to_sso.switchTo": "Switch account to {uiType}", + "claim.email_to_sso.title": "Switch Email/Password Account to {uiType}", + "claim.sso_to_email.confirm": "Confirm Password", + "claim.sso_to_email.description": "Upon changing your account type, you will only be able to login with your email and password.", "claim.sso_to_email.enterPwd": "Please enter a password.", - "claim.sso_to_email.pwdNotMatch": "Password do not match.", "claim.sso_to_email.newPwd": "New Password", - "claim.sso_to_email.confirm": "Confirm Password", + "claim.sso_to_email.pwdNotMatch": "Password do not match.", + "claim.sso_to_email.switchTo": "Switch {type} to email and password", "claim.sso_to_email.title": "Switch {type} Account to Email", - "claim.sso_to_email.description": "Upon changing your account type, you will only be able to login with your email and password.", "claim.sso_to_email_newPwd": "Enter a new password for your {team} {site} account", - "claim.sso_to_email.switchTo": "Switch {type} to email and password", "confirm_modal.cancel": "Cancel", - "create_comment.commentLength": "Comment length must be less than {max} characters.", - "create_comment.comment": "Add Comment", "create_comment.addComment": "Add a comment...", + "create_comment.comment": "Add Comment", + "create_comment.commentLength": "Comment length must be less than {max} characters.", "create_comment.commentTitle": "Comment", "create_comment.file": "File uploading", "create_comment.files": "Files uploading", "create_post.comment": "Comment", "create_post.post": "Post", - "create_post.write": "Write a message...", "create_post.tutorialTip": "<h4>Sending Messages</h4><p>Type here to write a message and press <strong>Enter</strong> to post it.</p><p>Click the <strong>Attachment</strong> button to upload an image or a file.</p>", + "create_post.write": "Write a message...", + "delete_channel.cancel": "Cancel", "delete_channel.channel": "channel", - "delete_channel.group": "group", "delete_channel.confirm": "Confirm DELETE Channel", - "delete_channel.question": "Are you sure you wish to delete the {display_name} {term}?", - "delete_channel.cancel": "Cancel", "delete_channel.del": "Delete", - "delete_post.warning": "This post has {count} comment(s) on it.", + "delete_channel.group": "group", + "delete_channel.question": "Are you sure you wish to delete the {display_name} {term}?", + "delete_post.cancel": "Cancel", "delete_post.comment": "Comment", - "delete_post.post": "Post", "delete_post.confirm": "Confirm {term} Delete", - "delete_post.question": "Are you sure you want to delete this {term}?", - "delete_post.cancel": "Cancel", "delete_post.del": "Delete", - "edit_channel_header_modal.error": "This channel header is too long, please enter a shorter one", - "edit_channel_header_modal.title": "Edit Header for {channel}", - "edit_channel_header_modal.description": "Edit the text appearing next to the channel name in the channel header.", + "delete_post.post": "Post", + "delete_post.question": "Are you sure you want to delete this {term}?", + "delete_post.warning": "This post has {count} comment(s) on it.", "edit_channel_header_modal.cancel": "Cancel", + "edit_channel_header_modal.description": "Edit the text appearing next to the channel name in the channel header.", + "edit_channel_header_modal.error": "This channel header is too long, please enter a shorter one", "edit_channel_header_modal.save": "Save", - "edit_channel_purpose_modal.error": "This channel purpose is too long, please enter a shorter one", - "edit_channel_purpose_modal.title1": "Edit Purpose", - "edit_channel_purpose_modal.title2": "Edit Purpose for ", - "edit_channel_purpose_modal.channel": "Channel", - "edit_channel_purpose_modal.group": "Group", + "edit_channel_header_modal.title": "Edit Header for {channel}", "edit_channel_purpose_modal.body": "Describe how this {type} should be used. This text appears in the channel list in the \"More...\" menu and helps others decide whether to join.", "edit_channel_purpose_modal.cancel": "Cancel", + "edit_channel_purpose_modal.channel": "Channel", + "edit_channel_purpose_modal.error": "This channel purpose is too long, please enter a shorter one", + "edit_channel_purpose_modal.group": "Group", "edit_channel_purpose_modal.save": "Save", - "edit_post.editPost": "Edit the post...", - "edit_post.edit": "Edit {title}", + "edit_channel_purpose_modal.title1": "Edit Purpose", + "edit_channel_purpose_modal.title2": "Edit Purpose for ", "edit_post.cancel": "Cancel", + "edit_post.edit": "Edit {title}", + "edit_post.editPost": "Edit the post...", "edit_post.save": "Save", - "email_verify.verified": "{siteName} Email Verified", - "email_verify.verifiedBody": "<p>Your email has been verified! Click <a href={url}>here</a> to log in.</p>", + "email_signup.address": "Email Address", + "email_signup.createTeam": "Create Team", + "email_signup.emailError": "Please enter a valid email address", + "email_signup.find": "Find my teams", "email_verify.almost": "{siteName}: You are almost done", "email_verify.notVerifiedBody": "Please verify your email address. Check your inbox for an email.", "email_verify.resend": "Resend Email", "email_verify.sent": " Verification email sent.", + "email_verify.verified": "{siteName} Email Verified", + "email_verify.verifiedBody": "<p>Your email has been verified! Click <a href={url}>here</a> to log in.</p>", "error_bar.preview_mode": "Preview Mode: Email notifications have not been configured", "file_attachment.download": "Download", - "file_info_preview.type": "File type ", "file_info_preview.size": "Size ", - "upload_overlay.info": "Drop a file to upload it.", - "file_upload.limited": "Uploads limited to {count} files maximum. Please use additional posts for more files.", - "file_upload.filesAbove": "Files above {max}MB could not be uploaded: {filenames}", + "file_info_preview.type": "File type ", "file_upload.fileAbove": "File above {max}MB could not be uploaded: {filename}", + "file_upload.filesAbove": "Files above {max}MB could not be uploaded: {filenames}", + "file_upload.limited": "Uploads limited to {count} files maximum. Please use additional posts for more files.", "file_upload.pasted": "Image Pasted at ", - "find_team.submitError": "Please enter a valid email address", - "find_team.placeholder": "you@domain.com", - "find_team.findTitle": "Find Your Team", + "find_team.email": "Email", "find_team.findDescription": "An email was sent with links to any teams to which you are a member.", + "find_team.findTitle": "Find Your Team", "find_team.getLinks": "Get an email with links to any teams to which you are a member.", - "find_team.email": "Email", + "find_team.placeholder": "you@domain.com", "find_team.send": "Send", - "get_link.copy": "Copy Link", + "find_team.submitError": "Please enter a valid email address", + "general_tab.chooseName": "Please choose a new name for your team", + "general_tab.codeDesc": "Click 'Edit' to regenerate Invite Code.", + "general_tab.codeLongDesc": "The Invite Code is used as part of the URL in the team invitation link created by **Get Team Invite Link** in the main menu. Regenerating creates a new team invitation link and invalidates the previous link.", + "general_tab.codeTitle": "Invite Code", + "general_tab.dirContact": "Contact your system administrator to turn on the team directory on the system home page.", + "general_tab.dirDisabled": "Team Directory has been disabled. Please ask a System Admin to enable the Team Directory in the System Console team settings.", + "general_tab.dirOff": "Team directory is turned off for this system.", + "general_tab.includeDirDesc": "Including this team will display the team name from the Team Directory section of the Home Page, and provide a link to the sign-in page.", + "general_tab.includeDirTitle": "Include this team in the Team Directory", + "general_tab.no": "No", + "general_tab.openInviteDesc": "When allowed, a link to account creation will be included on the sign-in page of this team and allow any visitor to sign-up.", + "general_tab.openInviteTitle": "Allow anyone to sign-up from login page", + "general_tab.regenerate": "Re-Generate", + "general_tab.required": "This field is required", + "general_tab.teamName": "Team Name", + "general_tab.teamNameInfo": "Set the name of the team as it appears on your sign-in screen and at the top of the left-hand sidebar.", + "general_tab.title": "General Settings", + "general_tab.yes": "Yes", "get_link.clipboard": " Link copied to clipboard.", "get_link.close": "Close", - "get_post_link_modal.title": "Copy Permalink", + "get_link.copy": "Copy Link", "get_post_link_modal.help": "The link below allows authorized users to see your post.", - "get_team_invite_link_modal.title": "Team Invite Link", + "get_post_link_modal.title": "Copy Permalink", "get_team_invite_link_modal.help": "Send teammates the link below for them to sign-up to this team site.", "get_team_invite_link_modal.helpDisabled": "User creation has been disabled for your team. Please ask your team administrator for details.", + "get_team_invite_link_modal.title": "Team Invite Link", + "intro_messages.DM": "This is the start of your direct message history with {teammate}.<br />Direct messages and files shared here are not shown to people outside this area.", + "intro_messages.anyMember": " Any member can join and read this channel.", + "intro_messages.beginning": "Beginning of {name}", + "intro_messages.channel": "channel", + "intro_messages.creator": "This is the start of the <strong>{name}</strong> {type}, created by <strong>{creator}</strong> on <strong>{date}</strong>", + "intro_messages.default": "<h4 class='channel-intro__title'>Beginning of {display_name}</h4><p class='channel-intro__content'><strong>Welcome to {display_name}!</strong><br/><br/>This is the first channel teammates see when they sign up - use it for posting updates everyone needs to know.</p>", + "intro_messages.group": "private group", + "intro_messages.invite": "Invite others to this {type}", + "intro_messages.inviteOthers": "Invite others to this team", + "intro_messages.noCreator": "This is the start of the {name} {type}, created on {date}.", + "intro_messages.offTopic": "<h4 class=\"channel-intro__title\">Beginning of {display_name}</h4><p class=\"channel-intro__content\">This is the start of {display_name}, a channel for non-work-related conversations.<br/></p>", + "intro_messages.onlyInvited": " Only invited members can see this private group.", + "intro_messages.setHeader": "Set a Header", + "intro_messages.teammate": "This is the start of your direct message history with this teammate. Direct messages and files shared here are not shown to people outside this area.", + "invite_member.addAnother": "Add another", + "invite_member.autoJoin": "People invited automatically join the <strong>{channel}</strong> channel.", + "invite_member.cancel": "Cancel", + "invite_member.content": "Email is currently disabled for your team, and email invitations cannot be sent. Contact your system administrator to enable email and email invitations.", + "invite_member.disabled": "User creation has been disabled for your team. Please ask your team administrator for details.", "invite_member.emailError": "Please enter a valid email address", "invite_member.firstname": "First name", + "invite_member.inviteLink": "Team Invite Link", "invite_member.lastname": "Last name", - "invite_member.modalTitle": "Discard Invitations?", - "invite_member.modalMessage": "You have unsent invitations, are you sure you want to discard them?", "invite_member.modalButton": "Yes, Discard", - "invite_member.addAnother": "Add another", - "invite_member.autoJoin": "People invited automatically join the <strong>{channel}</strong> channel.", + "invite_member.modalMessage": "You have unsent invitations, are you sure you want to discard them?", + "invite_member.modalTitle": "Discard Invitations?", + "invite_member.newMember": "Invite New Member", "invite_member.send": "Send Invitation", - "invite_member.sending": " Sending", "invite_member.send2": "Send Invitations", - "invite_member.inviteLink": "Team Invite Link", + "invite_member.sending": " Sending", "invite_member.teamInviteLink": "You can also invite people using the {link}.", - "invite_member.content": "Email is currently disabled for your team, and email invitations cannot be sent. Contact your system administrator to enable email and email invitations.", - "invite_member.disabled": "User creation has been disabled for your team. Please ask your team administrator for details.", - "invite_member.newMember": "Invite New Member", - "invite_member.cancel": "Cancel", "loading_screen.loading": "Loading", + "login.changed": " Sign-in method changed successfully", + "login.create": "Create one now", + "login.createTeam": "Create a new team", + "login.find": "Find your other teams", + "login.forgot": "I forgot my password", + "login.gitlab": "with GitLab", + "login.google": "with Google Apps", + "login.noAccount": "Don't have an account? ", + "login.on": "on {siteName}", + "login.or": "or", + "login.signTo": "Sign in to:", + "login.verified": " Email Verified", "login_email.badTeam": "Bad team name", - "login_email.emailReq": "An email is required", - "login_email.pwdReq": "A password is required", "login_email.email": "Email", + "login_email.emailReq": "An email is required", "login_email.pwd": "Password", + "login_email.pwdReq": "A password is required", "login_email.signin": "Sign in", "login_ldap.badTeam": "Bad team name", "login_ldap.idlReq": "An LDAP ID is required", - "login_ldap.pwdReq": "An LDAP password is required", - "login_ldap.username": "LDAP Username", "login_ldap.pwd": "LDAP Password", + "login_ldap.pwdReq": "An LDAP password is required", "login_ldap.signin": "Sign in", + "login_ldap.username": "LDAP Username", "login_username.badTeam": "Bad team name", - "login_username.usernameReq": "A username is required", + "login_username.pwd": "Password", "login_username.pwdReq": "A password is required", - "login_username.verifyEmailError": "Please verify your email address. Check your inbox for an email.", + "login_username.signin": "Sign in", "login_username.userNotFoundError": "We couldn't find an existing account matching your username for this team.", "login_username.username": "Username", - "login_username.pwd": "Password", - "login_username.signin": "Sign in", - "login.gitlab": "with GitLab", - "login.google": "with Google Apps", - "login.changed": " Sign-in method changed successfully", - "login.verified": " Email Verified", - "login.or": "or", - "login.forgot": "I forgot my password", - "login.noAccount": "Don't have an account? ", - "login.create": "Create one now", - "login.createTeam": "Create a new team", - "login.find": "Find your other teams", - "login.signTo": "Sign in to:", - "login.on": "on {siteName}", + "login_username.usernameReq": "A username is required", + "login_username.verifyEmailError": "Please verify your email address. Check your inbox for an email.", "member_item.add": " Add", "member_item.makeAdmin": "Make Admin", - "member_item.removeMember": "Remove Member", "member_item.member": "Member", + "member_item.removeMember": "Remove Member", + "member_team_item.confirmDemoteDescription": "If you demote yourself from the System Admin role and there is not another user with System Admin privileges, you'll need to re-assign a System Admin by accessing the Mattermost server through a terminal and running the following command.", "member_team_item.confirmDemoteRoleTitle": "Confirm demotion from System Admin role", "member_team_item.confirmDemotion": "Confirm Demotion", - "member_team_item.confirmDemoteDescription": "If you demote yourself from the System Admin role and there is not another user with System Admin privileges, you'll need to re-assign a System Admin by accessing the Mattermost server through a terminal and running the following command.", "member_team_item.confirmDemotionCmd": "platform -assign_role -team_name=\"yourteam\" -email=\"name@yourcompany.com\" -role=\"system_admin\"", - "member_team_item.member": "Member", - "member_team_item.systemAdmin": "System Admin", - "member_team_item.teamAdmin": "Team Admin", "member_team_item.inactive": "Inactive", - "member_team_item.makeAdmin": "Make Team Admin", - "member_team_item.makeMember": "Make Member", "member_team_item.makeActive": "Make Active", + "member_team_item.makeAdmin": "Make Team Admin", "member_team_item.makeInactive": "Make Inactive", + "member_team_item.makeMember": "Make Member", + "member_team_item.member": "Member", + "member_team_item.systemAdmin": "System Admin", + "member_team_item.teamAdmin": "Team Admin", + "members_popover.msg": "Message", + "members_popover.title": "Members", + "more_channels.close": "Close", + "more_channels.create": "Create New Channel", + "more_channels.createClick": "Click 'Create New Channel' to make a new one", "more_channels.join": "Join", "more_channels.noMore": "No more channels to join", - "more_channels.createClick": "Click 'Create New Channel' to make a new one", - "more_channels.close": "Close", "more_channels.title": "More Channels", - "more_channels.create": "Create New Channel", + "more_direct_channels.close": "Close", + "more_direct_channels.count": "{count} {member}", + "more_direct_channels.countTotal": "{count} {member} of {total} Total", "more_direct_channels.member": "Member", - "more_direct_channels.search": "Search members", "more_direct_channels.message": "Message", "more_direct_channels.notFound": "No users found :(", - "more_direct_channels.count": "{count} {member}", - "more_direct_channels.countTotal": "{count} {member} of {total} Total", + "more_direct_channels.search": "Search members", "more_direct_channels.title": "Direct Messages", - "more_direct_channels.close": "Close", - "msg_typing.someone": "Someone", - "msg_typing.isTyping": "{user} is typing...", "msg_typing.areTyping": "{users} and {last} are typing...", - "navbar_dropdown.inviteMember": "Invite New Member", - "navbar_dropdown.teamLink": "Get Team Invite Link", - "navbar_dropdown.manageMembers": "Manage Members", - "navbar_dropdown.teamSettings": "Team Settings", - "navbar_dropdown.console": "System Console", - "navbar_dropdown.switchTeam": "Switch to {team}", - "navbar_dropdown.create": "Create a New Team", - "navbar_dropdown.help": "Help", - "navbar_dropdown.report": "Report a Problem", - "navbar_dropdown.accountSettings": "Account Settings", - "navbar_dropdown.logout": "Logout", - "navbar_dropdown.about": "About Mattermost", - "navbar.viewInfo": "View Info", - "navbar.setHeader": "Set Channel Header...", - "navbar.setPurpose": "Set Channel Purpose...", + "msg_typing.isTyping": "{user} is typing...", + "msg_typing.someone": "Someone", "navbar.addMembers": "Add Members", + "navbar.click": "Click here", + "navbar.delete": "Delete Channel...", "navbar.leave": "Leave Channel", "navbar.manageMembers": "Manage Members", - "navbar.delete": "Delete Channel...", - "navbar.rename": "Rename Channel...", + "navbar.noHeader": "No channel header yet.{newline}{link} to add one.", "navbar.preferences": "Notification Preferences", + "navbar.rename": "Rename Channel...", + "navbar.setHeader": "Set Channel Header...", + "navbar.setPurpose": "Set Channel Purpose...", "navbar.toggle1": "Toggle sidebar", "navbar.toggle2": "Toggle sidebar", - "navbar.click": "Click here", - "navbar.noHeader": "No channel header yet.{newline}{link} to add one.", - "channel_flow.invalidName": "Invalid Channel Name", - "channel_flow.alreadyExist": "A channel with that URL already exists", - "channel_flow.channel": "Channel", - "channel_flow.group": "Group", - "channel_flow.changeUrlTitle": "Change {term} URL", - "channel_flow.set_url_title": "Set {term} URL", - "channel_flow.create": "Create {term}", - "channel_flow.changeUrlDescription": "Some characters are not allowed in URLs and may be removed.", - "channel_modal.nameEx": "E.g.: \"Bugs\", \"Marketing\", \"办公室恋情\"", - "channel_modal.displayNameError": "This field is required", - "channel_modal.group": "Group", - "channel_modal.privateGroup1": "Create a new private group with restricted membership. ", - "channel_modal.publicChannel1": "Create a public channel", - "channel_modal.channel": "Channel", - "channel_modal.publicChannel2": "Create a new public channel anyone can join. ", - "channel_modal.privateGroup2": "Create a private group", - "channel_modal.modalTitle": "New ", - "channel_modal.name": "Name", - "channel_modal.edit": "Edit", - "channel_modal.purpose": "Purpose", - "channel_modal.optional": "(optional)", - "channel_modal.descriptionHelp": "Describe how this {term} should be used.", - "channel_modal.cancel": "Cancel", - "channel_modal.createNew": "Create New ", + "navbar.viewInfo": "View Info", + "navbar_dropdown.about": "About Mattermost", + "navbar_dropdown.accountSettings": "Account Settings", + "navbar_dropdown.console": "System Console", + "navbar_dropdown.create": "Create a New Team", + "navbar_dropdown.help": "Help", + "navbar_dropdown.inviteMember": "Invite New Member", + "navbar_dropdown.logout": "Logout", + "navbar_dropdown.manageMembers": "Manage Members", + "navbar_dropdown.report": "Report a Problem", + "navbar_dropdown.switchTeam": "Switch to {team}", + "navbar_dropdown.teamLink": "Get Team Invite Link", + "navbar_dropdown.teamSettings": "Team Settings", + "password_form.change": "Change my password", + "password_form.click": "Click <a href={url}>here</a> to log in.", + "password_form.enter": "Enter a new password for your {teamDisplayName} {siteName} account.", "password_form.error": "Please enter at least {chars} characters.", - "password_form.update": "Your password has been updated successfully.", "password_form.pwd": "Password", - "password_form.click": "Click <a href={url}>here</a> to log in.", "password_form.title": "Password Reset", - "password_form.enter": "Enter a new password for your {teamDisplayName} {siteName} account.", - "password_form.change": "Change my password", - "password_send.error": "Please enter a valid email address.", - "password_send.link": "<p>A password reset link has been sent to <b>{email}</b> for your <b>{teamDisplayName}</b> team on {hostname}.</p>", + "password_form.update": "Your password has been updated successfully.", "password_send.checkInbox": "Please check your inbox.", - "password_send.email": "Email", - "password_send.title": "Password Reset", "password_send.description": "To reset your password, enter the email address you used to sign up for {teamName}.", + "password_send.email": "Email", + "password_send.error": "Please enter a valid email address.", + "password_send.link": "<p>A password reset link has been sent to <b>{email}</b> for your <b>{teamDisplayName}</b> team on {hostname}.</p>", "password_send.reset": "Reset my password", - "members_popover.msg": "Message", - "members_popover.title": "Members", + "password_send.title": "Password Reset", "post_attachment.collapse": "▲ collapse text", "post_attachment.more": "▼ read more", - "post_body.plusOne": " plus 1 other file", - "post_body.plusMore": " plus {count} other files", "post_body.commentedOn": "Commented on {name}{apostrophe} message: ", - "post_body.retry": "Retry", "post_body.deleted": "(message deleted)", + "post_body.plusMore": " plus {count} other files", + "post_body.plusOne": " plus 1 other file", + "post_body.retry": "Retry", "post_delete.notPosted": "Comment could not be posted", - "post_delete.someone": "Someone deleted the message on which you tried to post a comment.", "post_delete.okay": "Okay", + "post_delete.someone": "Someone deleted the message on which you tried to post a comment.", "post_focus_view.beginning": "Beginning of Channel Archives", - "post_info.reply": "Reply", - "post_info.permalink": "Permalink", "post_info.del": "Delete", "post_info.edit": "Edit", - "posts_view.newMsg": "New Messages", + "post_info.permalink": "Permalink", + "post_info.reply": "Reply", "posts_view.loadMore": "Load more messages", - "register_app.required": "Required", - "register_app.optional": "Optional", - "register_app.nameError": "Application name must be filled in.", - "register_app.homepageError": "Homepage must be filled in.", - "register_app.callbackError": "At least one callback URL must be filled in.", - "register_app.title": "Register a New Application", - "register_app.name": "Application Name", - "register_app.homepage": "Homepage URL", - "register_app.description": "Description", + "posts_view.newMsg": "New Messages", "register_app.callback": "Callback URL", + "register_app.callbackError": "At least one callback URL must be filled in.", "register_app.cancel": "Cancel", - "register_app.register": "Register", - "register_app.credentialsTitle": "Your Application Credentials", "register_app.clientId": "Client ID", "register_app.clientSecret": "Client Secret", + "register_app.close": "Close", "register_app.credentialsDescription": "Save these somewhere SAFE and SECURE. Treat your Client ID as your app's username and your Client Secret as the app's password.", "register_app.credentialsSave": "I have saved both my Client Id and Client Secret somewhere safe", - "register_app.close": "Close", + "register_app.credentialsTitle": "Your Application Credentials", + "register_app.description": "Description", "register_app.dev": "Developer Applications", + "register_app.homepage": "Homepage URL", + "register_app.homepageError": "Homepage must be filled in.", + "register_app.name": "Application Name", + "register_app.nameError": "Application name must be filled in.", + "register_app.optional": "Optional", + "register_app.register": "Register", + "register_app.required": "Required", + "register_app.title": "Register a New Application", "removed_channel.channelName": "the channel", - "removed_channel.someone": "Someone", "removed_channel.from": "Removed from ", - "removed_channel.remover": "{remover} removed you from {channel}", "removed_channel.okay": "Okay", - "rename_channel.required": "This field is required", - "rename_channel.maxLength": "This field must be less than 22 characters", - "rename_channel.lowercase": "Must be lowercase alphanumeric characters", - "rename_channel.handle": "Handle", + "removed_channel.remover": "{remover} removed you from {channel}", + "removed_channel.someone": "Someone", + "rename_channel.cancel": "Cancel", "rename_channel.defaultError": " - Cannot be changed for the default channel", + "rename_channel.displayName": "Display Name", "rename_channel.displayNameHolder": "Enter display name", + "rename_channel.handle": "Handle", "rename_channel.handleHolder": "lowercase alphanumeric's only", - "rename_channel.close": "Close", - "rename_channel.title": "Rename Channel", - "rename_channel.displayName": "Display Name", - "rename_channel.cancel": "Cancel", + "rename_channel.lowercase": "Must be lowercase alphanumeric characters", + "rename_channel.maxLength": "This field must be less than 22 characters", + "rename_channel.required": "This field is required", "rename_channel.save": "Save", + "rename_channel.title": "Rename Channel", "rhs_comment.comment": "Comment", - "rhs_comment.permalink": "Permalink", - "rhs_comment.edit": "Edit", "rhs_comment.del": "Delete", + "rhs_comment.edit": "Edit", + "rhs_comment.permalink": "Permalink", "rhs_comment.retry": "Retry", "rhs_header.details": "Message Details", + "rhs_root.del": "Delete", "rhs_root.direct": "Direct Message", - "rhs_root.permalink": "Permalink", "rhs_root.edit": "Edit", - "rhs_root.del": "Delete", - "search_bar.search": "Search", + "rhs_root.permalink": "Permalink", "search_bar.cancel": "Cancel", + "search_bar.search": "Search", "search_bar.usage": "<h4>Search Options</h4><ul><li><span>Use </span><b>\"quotation marks\"</b><span> to search for phrases</span></li><li><span>Use </span><b>from:</b><span> to find posts from specific users and </span><b>in:</b><span> to find posts in specific channels</span></li></ul>", "search_header.results": "Search Results", "search_header.title2": "Recent Mentions", "search_item.direct": "Direct Message", "search_item.jump": "Jump", - "search_results.usage": "<ul><li>Use <b>\"quotation marks\"</b> to search for phrases</li><li>Use <b>from:</b> to find posts from specific users and <b>in:</b> to find posts in specific channels</li></ul>", - "search_results.noResults": "NO RESULTS", "search_results.because": "<ul><li>If you're searching a partial phrase (ex. searching \"rea\", looking for \"reach\" or \"reaction\"), append a * to your search term</li><li>Due to the volume of results, two letter searches and common words like \"this\", \"a\" and \"is\" won't appear in search results</li></ul>", - "setting_item_max.save": "Save", + "search_results.noResults": "NO RESULTS", + "search_results.usage": "<ul><li>Use <b>\"quotation marks\"</b> to search for phrases</li><li>Use <b>from:</b> to find posts from specific users and <b>in:</b> to find posts in specific channels</li></ul>", "setting_item_max.cancel": "Cancel", + "setting_item_max.save": "Save", "setting_item_min.edit": "Edit", - "setting_picture.save": "Save", + "setting_picture.cancel": "Cancel", "setting_picture.help": "Upload a profile picture in either JPG or PNG format, at least {width}px in width and {height}px height.", + "setting_picture.save": "Save", "setting_picture.select": "Select", - "setting_picture.cancel": "Cancel", + "setting_upload.import": "Import", "setting_upload.noFile": "No file selected.", "setting_upload.select": "Select file", - "setting_upload.import": "Import", - "sidebar_header.tutorial": "<h4>Main Menu</h4><p>The <strong>Main Menu</strong> is where you can <strong>Invite New Members</strong>, access your <strong>Account Settings</strong> and set your <strong>Theme Color</strong>.</p><p>Team administrators can also access their <strong>Team Settings</strong> from this menu.</p><p>System administrators will find a <strong>System Console</strong> option to administrate the entire system.</p>", - "sidebar_right_menu.inviteNew": "Invite New Member", - "sidebar_right_menu.teamLink": "Get Team Invite Link", - "sidebar_right_menu.teamSettings": "Team Settings", - "sidebar_right_menu.manageMembers": "Manage Members", - "sidebar_right_menu.console": "System Console", - "sidebar_right_menu.help": "Help", - "sidebar_right_menu.report": "Report a Problem", - "sidebar_right_menu.accountSettings": "Account Settings", - "sidebar_right_menu.logout": "Logout", + "sidebar.channels": "Channels", + "sidebar.createChannel": "Create new channel", + "sidebar.createGroup": "Create new group", + "sidebar.direct": "Direct Messages", + "sidebar.more": "More ({count})", + "sidebar.moreElips": "More...", + "sidebar.pg": "Private Groups", + "sidebar.removeList": "Remove from list", "sidebar.tutorialScreen1": "<h4>Channels</h4><p><strong>Channels</strong> organize conversations across different topics. They’re open to everyone on your team. To send private communications use <strong>Direct Messages</strong> for a single person or <strong>Private Groups</strong> for multiple people.</p>", "sidebar.tutorialScreen2": "<h4>\"Town Square\" and \"Off-Topic\" channels</h4><p>Here are two public channels to start:</p><p><strong>Town Square</strong> is a place for team-wide communication. Everyone in your team is a member of this channel.</p><p><strong>Off-Topic</strong> is a place for fun and humor outside of work-related channels. You and your team can decide what other channels to create.</p>", "sidebar.tutorialScreen3": "<h4>Creating and Joining Channels</h4><p>Click <strong>\"More...\"</strong> to create a new channel or join an existing one.</p><p>You can also create a new channel or private group by clicking the <strong>\"+\" symbol</strong> next to the channel or private group header.</p>", - "sidebar.removeList": "Remove from list", - "sidebar.more": "More ({count})", - "sidebar.createChannel": "Create new channel", - "sidebar.createGroup": "Create new group", "sidebar.unreadAbove": "Unread post(s) above", "sidebar.unreadBelow": "Unread post(s) below", - "sidebar.channels": "Channels", - "sidebar.moreElips": "More...", - "sidebar.pg": "Private Groups", - "sidebar.direct": "Direct Messages", - "signup_team_complete.completed": "You've already completed the signup process for this invitation or this invitation has expired.", - "signup_team_confirm.title": "Sign up Complete", - "signup_team_confirm.checkEmail": "Please check your email: <strong>{email}</strong><br />Your email contains a link to set up your team", - "signup_team.noTeams": "There are no teams include in the Team Directory and team creation has been disabled.", + "sidebar_header.tutorial": "<h4>Main Menu</h4><p>The <strong>Main Menu</strong> is where you can <strong>Invite New Members</strong>, access your <strong>Account Settings</strong> and set your <strong>Theme Color</strong>.</p><p>Team administrators can also access their <strong>Team Settings</strong> from this menu.</p><p>System administrators will find a <strong>System Console</strong> option to administrate the entire system.</p>", + "sidebar_right_menu.accountSettings": "Account Settings", + "sidebar_right_menu.console": "System Console", + "sidebar_right_menu.help": "Help", + "sidebar_right_menu.inviteNew": "Invite New Member", + "sidebar_right_menu.logout": "Logout", + "sidebar_right_menu.manageMembers": "Manage Members", + "sidebar_right_menu.report": "Report a Problem", + "sidebar_right_menu.teamLink": "Get Team Invite Link", + "sidebar_right_menu.teamSettings": "Team Settings", "signup_team.choose": "Choose a Team", "signup_team.createTeam": "Or Create a Team", "signup_team.disabled": "Team creation has been disabled. Please contact an administrator for access.", + "signup_team.noTeams": "There are no teams include in the Team Directory and team creation has been disabled.", "signup_team.none": "No team creation method has been enabled. Please contact an administrator for access.", - "signup_user_completed.required": "This field is required", - "signup_user_completed.validEmail": "Please enter a valid email address", - "signup_user_completed.reserved": "This username is reserved, please choose a new one.", - "signup_user_completed.usernameLength": "Username must begin with a letter, and contain between {min} to {max} lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'.", - "signup_user_completed.passwordLength": "Please enter at least {min} characters", - "signup_user_completed.expired": "You've already completed the signup process for this invitation or this invitation has expired.", + "signup_team_complete.completed": "You've already completed the signup process for this invitation or this invitation has expired.", + "signup_team_confirm.checkEmail": "Please check your email: <strong>{email}</strong><br />Your email contains a link to set up your team", + "signup_team_confirm.title": "Sign up Complete", + "signup_user_completed.choosePwd": "Choose your password", + "signup_user_completed.chooseUser": "Choose your username", + "signup_user_completed.create": "Create Account", "signup_user_completed.emailHelp": "Valid email required for sign-up", - "signup_user_completed.userHelp": "Username must begin with a letter, and contain between {min} to {max} lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'", "signup_user_completed.emailIs": "Your email address is <strong>{email}</strong>. You'll use this address to sign in to {siteName}.", - "signup_user_completed.whatis": "What's your email address?", + "signup_user_completed.expired": "You've already completed the signup process for this invitation or this invitation has expired.", "signup_user_completed.gitlab": "with GitLab", "signup_user_completed.google": "with Google", - "signup_user_completed.chooseUser": "Choose your username", - "signup_user_completed.choosePwd": "Choose your password", - "signup_user_completed.create": "Create Account", - "signup_user_completed.or": "or", + "signup_user_completed.lets": "Let's create your account", "signup_user_completed.none": "No user creation method has been enabled. Please contact an administrator for access.", - "signup_user_completed.welcome": "Welcome to:", "signup_user_completed.onSite": "on {siteName}", - "signup_user_completed.lets": "Let's create your account", + "signup_user_completed.or": "or", + "signup_user_completed.passwordLength": "Please enter at least {min} characters", + "signup_user_completed.required": "This field is required", + "signup_user_completed.reserved": "This username is reserved, please choose a new one.", + "signup_user_completed.userHelp": "Username must begin with a letter, and contain between {min} to {max} lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'", + "signup_user_completed.usernameLength": "Username must begin with a letter, and contain between {min} to {max} lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'.", + "signup_user_completed.validEmail": "Please enter a valid email address", + "signup_user_completed.welcome": "Welcome to:", + "signup_user_completed.whatis": "What's your email address?", + "sso_signup.find": "Find my teams", + "sso_signup.gitlab": "Create team with GitLab Account", + "sso_signup.google": "Create team with Google Apps Account", + "sso_signup.length_error": "Name must be 3 or more characters up to a maximum of 15", + "sso_signup.teamName": "Enter name of new team", + "sso_signup.team_error": "Please enter a team name", "suggestion.mention.all": "Notifies everyone in the team", "suggestion.mention.channel": "Notifies everyone in the channel", - "suggestion.search.public": "Public Channels", "suggestion.search.private": "Public Groups", - "team_export_tab.exporting": " Exporting...", - "team_export_tab.ready": " Ready for ", + "suggestion.search.public": "Public Channels", "team_export_tab.download": "download", - "team_export_tab.unable": " Unable to export: {error}", "team_export_tab.export": "Export", "team_export_tab.exportTeam": "Export your team", - "general_tab.dirDisabled": "Team Directory has been disabled. Please ask a System Admin to enable the Team Directory in the System Console team settings.", - "general_tab.required": "This field is required", - "general_tab.chooseName": "Please choose a new name for your team", - "general_tab.includeDirTitle": "Include this team in the Team Directory", - "general_tab.yes": "Yes", - "general_tab.no": "No", - "general_tab.dirOff": "Team directory is turned off for this system.", - "general_tab.openInviteTitle": "Allow anyone to sign-up from login page", - "general_tab.codeTitle": "Invite Code", - "general_tab.codeDesc": "Click 'Edit' to regenerate Invite Code.", - "general_tab.teamNameInfo": "Set the name of the team as it appears on your sign-in screen and at the top of the left-hand sidebar.", - "general_tab.includeDirDesc": "Including this team will display the team name from the Team Directory section of the Home Page, and provide a link to the sign-in page.", - "general_tab.dirContact": "Contact your system administrator to turn on the team directory on the system home page.", - "general_tab.openInviteDesc": "When allowed, a link to account creation will be included on the sign-in page of this team and allow any visitor to sign-up.", - "general_tab.regenerate": "Re-Generate", - "general_tab.codeLongDesc": "The Invite Code is used as part of the URL in the team invitation link created by **Get Team Invite Link** in the main menu. Regenerating creates a new team invitation link and invalidates the previous link.", - "general_tab.teamName": "Team Name", - "general_tab.title": "General Settings", - "team_import_tab.importSlack": "Import from Slack (Beta)", + "team_export_tab.exporting": " Exporting...", + "team_export_tab.ready": " Ready for ", + "team_export_tab.unable": " Unable to export: {error}", + "team_import_tab.failure": " Import failure: ", + "team_import_tab.import": "Import", "team_import_tab.importHelp": "<p>To import a team from Slack go to Slack > Team Settings > Import/Export Data > Export > Start Export. Slack does not allow you to export files, images, private groups or direct messages stored in Slack. Therefore, Slack import to Mattermost only supports importing of text messages in your Slack team's public channels.</p><p>The Slack import to Mattermost is in 'Beta'. Slack bot posts do not yet import and Slack @mentions are not currently supported.</p>", + "team_import_tab.importSlack": "Import from Slack (Beta)", "team_import_tab.importing": " Importing...", "team_import_tab.successful": " Import successful: ", "team_import_tab.summary": "View Summary", - "team_import_tab.failure": " Import failure: ", - "team_import_tab.import": "Import", - "team_member_modal.members": "{team} Members", "team_member_modal.close": "Close", + "team_member_modal.members": "{team} Members", + "team_settings_modal.exportTab": "Export", "team_settings_modal.generalTab": "General", "team_settings_modal.importTab": "Import", - "team_settings_modal.exportTab": "Export", "team_settings_modal.title": "Team Settings", - "choose_auth_page.gitlabCreate": "Create new team with GitLab Account", - "choose_auth_page.googleCreate": "Create new team with Google Apps Account", - "choose_auth_page.emailCreate": "Create new team with email address", - "choose_auth_page.noSignup": "No sign-up methods configured, please contact your system administrator.", - "choose_auth_page.find": "Find my teams", - "team_signup_display_name.required": "This field is required", + "team_signup_display_name.back": "Back to previous step", "team_signup_display_name.charLength": "Name must be 4 or more characters up to a maximum of 15", - "team_signup_display_name.teamName": "Team Name", "team_signup_display_name.nameHelp": "Name your team in any language. Your team name shows in menus and headings.", "team_signup_display_name.next": "Next", - "team_signup_display_name.back": "Back to previous step", - "team_signup_email.validEmail": "Please enter a valid email address", - "team_signup_email.different": "Please use a different email than the one used at signup", + "team_signup_display_name.required": "This field is required", + "team_signup_display_name.teamName": "Team Name", "team_signup_email.address": "Email Address", - "team_signup_password.passwordError": "Please enter at least {chars} characters", + "team_signup_email.different": "Please use a different email than the one used at signup", + "team_signup_email.validEmail": "Please enter a valid email address", + "team_signup_password.agreement": "By proceeding to create your account and use {siteName}, you agree to our <a href='/static/help/terms.html'>Terms of Service</a> and <a href='/static/help/privacy.html'>Privacy Policy</a>. If you do not agree, you cannot use {siteName}.", + "team_signup_password.back": "Back to previous step", + "team_signup_password.choosePwd": "Choose your password", "team_signup_password.creating": "Creating team...", - "team_signup_password.yourPassword": "Your password", - "team_signup_password.selectPassword": "Select a password that you'll use to login with your email address:", "team_signup_password.email": "Email", - "team_signup_password.choosePwd": "Choose your password", - "team_signup_password.hint": "Passwords must contain {min} to {max} characters. Your password will be strongest if it contains a mix of symbols, numbers, and upper and lowercase characters.", "team_signup_password.finish": "Finish", - "team_signup_password.agreement": "By proceeding to create your account and use {siteName}, you agree to our <a href='/static/help/terms.html'>Terms of Service</a> and <a href='/static/help/privacy.html'>Privacy Policy</a>. If you do not agree, you cannot use {siteName}.", - "team_signup_password.back": "Back to previous step", + "team_signup_password.hint": "Passwords must contain {min} to {max} characters. Your password will be strongest if it contains a mix of symbols, numbers, and upper and lowercase characters.", + "team_signup_password.passwordError": "Please enter at least {chars} characters", + "team_signup_password.selectPassword": "Select a password that you'll use to login with your email address:", + "team_signup_password.yourPassword": "Your password", "team_signup_send_invites.addInvitation": "Add Invitation", + "team_signup_send_invites.back": "Back to previous step", + "team_signup_send_invites.disabled": "Email is currently disabled for your team, and emails cannot be sent. Contact your system administrator to enable email and email invitations.", + "team_signup_send_invites.forNow": "for now.", + "team_signup_send_invites.next": "Next", "team_signup_send_invites.prefer": "if you prefer, you can invite team members later<br /> and ", "team_signup_send_invites.skip": "skip this step ", - "team_signup_send_invites.forNow": "for now.", - "team_signup_send_invites.disabled": "Email is currently disabled for your team, and emails cannot be sent. Contact your system administrator to enable email and email invitations.", "team_signup_send_invites.title": "Invite Team Members", - "team_signup_send_invites.next": "Next", - "team_signup_send_invites.back": "Back to previous step", - "team_signup_url.required": "This field is required", - "team_signup_url.regex": "Use only lower case letters, numbers and dashes. Must start with a letter and can't end in a dash.", + "team_signup_url.back": "Back to previous step", "team_signup_url.charLength": "Name must be 4 or more characters up to a maximum of 15", + "team_signup_url.hint": "<li>Short and memorable is best</li><li>Use lowercase letters, numbers and dashes</li><li>Must start with a letter and can't end in a dash</li>", + "team_signup_url.next": "Next", + "team_signup_url.regex": "Use only lower case letters, numbers and dashes. Must start with a letter and can't end in a dash.", + "team_signup_url.required": "This field is required", "team_signup_url.taken": "URL is taken or contains a reserved word", - "team_signup_url.unavailable": "This URL is unavailable. Please try another.", "team_signup_url.teamUrl": "Team URL", + "team_signup_url.unavailable": "This URL is unavailable. Please try another.", "team_signup_url.webAddress": "Choose the web address of your new team:", - "team_signup_url.hint": "<li>Short and memorable is best</li><li>Use lowercase letters, numbers and dashes</li><li>Must start with a letter and can't end in a dash</li>", - "team_signup_url.next": "Next", - "team_signup_url.back": "Back to previous step", - "team_signup_username.reserved": "This username is reserved, please choose a new one.", - "team_signup_username.invalid": "Username must begin with a letter, and contain between {min} to {max} characters in total, which may be numbers, lowercase letters, or any of the symbols '.', '-', or '_'", + "team_signup_username.back": "Back to previous step", + "team_signup_username.chooseUsername": "Choose your username", "team_signup_username.hint": "Usernames must begin with a letter and contain between {min} to {max} characters made up of lowercase letters, numbers, and the symbols '.', '-' and '_'", - "team_signup_username.username": "Your username", + "team_signup_username.invalid": "Username must begin with a letter, and contain between {min} to {max} characters in total, which may be numbers, lowercase letters, or any of the symbols '.', '-', or '_'", "team_signup_username.memorable": "Select a memorable username that makes it easy for teammates to identify you:", - "team_signup_username.chooseUsername": "Choose your username", "team_signup_username.next": "Next", - "team_signup_username.back": "Back to previous step", + "team_signup_username.reserved": "This username is reserved, please choose a new one.", + "team_signup_username.username": "Your username", + "team_signup_welcome.address": "Email Address", + "team_signup_welcome.admin": "Your account will administer the new team site. <br />You can add other administrators later.", + "team_signup_welcome.confirm": "Please confirm your email address:", + "team_signup_welcome.different": "Use a different email", + "team_signup_welcome.instead": "Use this instead", + "team_signup_welcome.lets": "Let's set up your new team", "team_signup_welcome.storageError": "This service requires local storage to be enabled. Please enable it or exit private browsing.", "team_signup_welcome.validEmailError": "Please enter a valid email address", - "team_signup_welcome.address": "Email Address", "team_signup_welcome.welcome": "Welcome to:", - "team_signup_welcome.lets": "Let's set up your new team", - "team_signup_welcome.confirm": "Please confirm your email address:", - "team_signup_welcome.admin": "Your account will administer the new team site. <br />You can add other administrators later.", "team_signup_welcome.yes": "Yes, this address is correct", - "team_signup_welcome.instead": "Use this instead", - "team_signup_welcome.different": "Use a different email", - "email_signup.emailError": "Please enter a valid email address", - "email_signup.address": "Email Address", - "email_signup.createTeam": "Create Team", - "email_signup.find": "Find my teams", - "sso_signup.team_error": "Please enter a team name", - "sso_signup.length_error": "Name must be 3 or more characters up to a maximum of 15", - "sso_signup.teamName": "Enter name of new team", - "sso_signup.gitlab": "Create team with GitLab Account", - "sso_signup.google": "Create team with Google Apps Account", - "sso_signup.find": "Find my teams", "textbox.edit": "Edit message", - "textbox.preview": "Preview", "textbox.help": "Help", - "tutorial_intro.screenOne": "<h3>Welcome to:</h3><h1>Mattermost</h1><p>Your team communication all in one place, instantly searchable and available anywhere</p><p>Keep your team connected to help them achieve what matters most.</p>", - "tutorial_intro.screenTwo": "<h3>How Mattermost works:</h3><p>Communication happens in public discussion channels, private groups and direct messages.</p><p>Everything is archived and searchable from any web-enabled desktop, laptop or phone.</p>", - "tutorial_intro.invite": "Invite teammates", - "tutorial_intro.teamInvite": "Team Invite", - "tutorial_intro.support": "Need anything, just email us at ", + "textbox.preview": "Preview", "tutorial_intro.allSet": "You’re all set", - "tutorial_intro.whenReady": " when you’re ready.", "tutorial_intro.end": "Click “Next” to enter Town Square. This is the first channel teammates see when they sign up. Use it for posting updates everyone needs to know.", + "tutorial_intro.invite": "Invite teammates", "tutorial_intro.next": "Next", + "tutorial_intro.screenOne": "<h3>Welcome to:</h3><h1>Mattermost</h1><p>Your team communication all in one place, instantly searchable and available anywhere</p><p>Keep your team connected to help them achieve what matters most.</p>", + "tutorial_intro.screenTwo": "<h3>How Mattermost works:</h3><p>Communication happens in public discussion channels, private groups and direct messages.</p><p>Everything is archived and searchable from any web-enabled desktop, laptop or phone.</p>", "tutorial_intro.skip": "Skip tutorial", - "tutorial_tip.ok": "Okay", + "tutorial_intro.support": "Need anything, just email us at ", + "tutorial_intro.teamInvite": "Team Invite", + "tutorial_intro.whenReady": " when you’re ready.", "tutorial_tip.next": "Next", - "tutorial_tip.seen": "Seen this before? ", + "tutorial_tip.ok": "Okay", "tutorial_tip.out": "Opt out of these tips.", - "user_profile.notShared": "Email not shared", - "user.settings.custom_theme.sidebarBg": "Sidebar BG", - "user.settings.custom_theme.sidebarText": "Sidebar Text", - "user.settings.custom_theme.sidebarHeaderBg": "Sidebar Header BG", - "user.settings.custom_theme.sidebarHeaderTextColor": "Sidebar Header Text", - "user.settings.custom_theme.sidebarUnreadText": "Sidebar Unread Text", - "user.settings.custom_theme.sidebarTextHoverBg": "Sidebar Text Hover BG", - "user.settings.custom_theme.sidebarTextActiveBorder": "Sidebar Text Active Border", - "user.settings.custom_theme.sidebarTextActiveColor": "Sidebar Text Active Color", - "user.settings.custom_theme.onlineIndicator": "Online Indicator", - "user.settings.custom_theme.awayIndicator": "Away Indicator", - "user.settings.custom_theme.mentionBj": "Mention Jewel BG", - "user.settings.custom_theme.mentionColor": "Mention Jewel Text", - "user.settings.custom_theme.centerChannelBg": "Center Channel BG", - "user.settings.custom_theme.centerChannelColor": "Center Channel Text", - "user.settings.custom_theme.newMessageSeparator": "New Message Separator", - "user.settings.custom_theme.linkColor": "Link Color", - "user.settings.custom_theme.buttonBg": "Button BG", - "user.settings.custom_theme.buttonColor": "Button Text", - "user.settings.custom_theme.mentionHighlightBg": "Mention Highlight BG", - "user.settings.custom_theme.mentionHighlightLink": "Mention Highlight Link", - "user.settings.custom_theme.codeTheme": "Code Theme", - "user.settings.custom_theme.copyPaste": "Copy and paste to share theme colors:", - "user.settings.import_theme.submitError": "Invalid format, please try copying and pasting in again.", - "user.settings.import_theme.importHeader": "Import Slack Theme", - "user.settings.import_theme.importBody": "To import a theme, go to a Slack team and look for “Preferences -> Sidebar Theme”. Open the custom theme option, copy the theme color values and paste them here:", - "user.settings.import_theme.cancel": "Cancel", - "user.settings.import_theme.submit": "Submit", - "user.settings.cmds.request_type_post": "POST", - "user.settings.cmds.request_type_get": "GET", + "tutorial_tip.seen": "Seen this before? ", + "upload_overlay.info": "Drop a file to upload it.", + "user.settings.advance.embed_preview": "Show preview snippet of links below message", + "user.settings.advance.enabled": "enabled", + "user.settings.advance.feature": " Feature ", + "user.settings.advance.features": " Features ", + "user.settings.advance.markdown_preview": "Show markdown preview option in message input box", + "user.settings.advance.off": "Off", + "user.settings.advance.on": "On", + "user.settings.advance.preReleaseDesc": "Check any pre-released features you'd like to preview. You may also need to refresh the page before the setting will take effect.", + "user.settings.advance.preReleaseTitle": "Preview pre-release features", + "user.settings.advance.sendDesc": "If enabled 'Enter' inserts a new line and 'Ctrl + Enter' submits the message.", + "user.settings.advance.sendTitle": "Send messages on Ctrl + Enter", + "user.settings.advance.title": "Advanced Settings", + "user.settings.cmds.add": "Add", + "user.settings.cmds.add_desc": "Create slash commands to send events to external integrations and receive a response. For example typing `/patient Joe Smith` could bring back search results from your internal health records management system for the name “Joe Smith”. Please see <a href=\"http://docs.mattermost.com/developer/slash-commands.html\">Slash commands documentation</a> for detailed instructions.", "user.settings.cmds.add_display_name.placeholder": "Example: \"Search patient records\"", - "user.settings.cmds.add_username.placeholder": "Username", + "user.settings.cmds.add_new": "Add a new command", "user.settings.cmds.add_trigger.placeholder": "Command trigger e.g. \"hello\" not including the slash", - "user.settings.cmds.auto_complete_desc.placeholder": "Example: \"Returns search results for patient records\"", - "user.settings.cmds.auto_complete_hint.placeholder": "Example: [Patient Name]", - "user.settings.cmds.url.placeholder": "Must start with http:// or https://", - "user.settings.cmds.auto_complete.yes": "yes", - "user.settings.cmds.auto_complete.no": "no", - "user.settings.cmds.trigger": "Command Trigger Word: ", - "user.settings.cmds.url": "Request URL: ", - "user.settings.cmds.request_type": "Request Method: ", - "user.settings.cmds.username": "Response Username: ", - "user.settings.cmds.icon_url": "Response Icon: ", + "user.settings.cmds.add_username.placeholder": "Username", "user.settings.cmds.auto_complete": "Autocomplete: ", - "user.settings.cmds.auto_complete_hint": "Autocomplete Hint: ", + "user.settings.cmds.auto_complete.no": "no", + "user.settings.cmds.auto_complete.yes": "yes", "user.settings.cmds.auto_complete_desc": "Autocomplete Description: ", + "user.settings.cmds.auto_complete_desc.placeholder": "Example: \"Returns search results for patient records\"", + "user.settings.cmds.auto_complete_desc_desc": "Optional short description of slash command for the autocomplete list.", + "user.settings.cmds.auto_complete_help": " Show this command in the autocomplete list.", + "user.settings.cmds.auto_complete_hint": "Autocomplete Hint: ", + "user.settings.cmds.auto_complete_hint.placeholder": "Example: [Patient Name]", + "user.settings.cmds.auto_complete_hint_desc": "Optional hint in the autocomplete list about parameters needed for command.", + "user.settings.cmds.cmd_display_name": "Brief description of slash command to show in listings.", "user.settings.cmds.display_name": "Descriptive Label: ", - "user.settings.cmds.token": "Token: ", - "user.settings.cmds.regen": "Regen Token", - "user.settings.cmds.none": "None", "user.settings.cmds.existing": "Existing commands", - "user.settings.cmds.add_desc": "Create slash commands to send events to external integrations and receive a response. For example typing `/patient Joe Smith` could bring back search results from your internal health records management system for the name “Joe Smith”. Please see <a href=\"http://docs.mattermost.com/developer/slash-commands.html\">Slash commands documentation</a> for detailed instructions.", - "user.settings.cmds.add_new": "Add a new command", + "user.settings.cmds.icon_url": "Response Icon: ", + "user.settings.cmds.icon_url_desc": "Choose a profile picture override for the post responses to this slash command. Enter the URL of a .png or .jpg file at least 128 pixels by 128 pixels.", + "user.settings.cmds.none": "None", + "user.settings.cmds.regen": "Regen Token", + "user.settings.cmds.request_type": "Request Method: ", + "user.settings.cmds.request_type_desc": "The type of command request issued to the Request URL.", + "user.settings.cmds.request_type_get": "GET", + "user.settings.cmds.request_type_post": "POST", + "user.settings.cmds.token": "Token: ", + "user.settings.cmds.trigger": "Command Trigger Word: ", "user.settings.cmds.trigger_desc": "Examples: /patient, /client, /employee Reserved: /echo, /join, /logout, /me, /shrug", + "user.settings.cmds.url": "Request URL: ", + "user.settings.cmds.url.placeholder": "Must start with http:// or https://", "user.settings.cmds.url_desc": "The callback URL to receive the HTTP POST or GET event request when the slash command is run.", - "user.settings.cmds.request_type_desc": "The type of command request issued to the Request URL.", + "user.settings.cmds.username": "Response Username: ", "user.settings.cmds.username_desc": "Choose a username override for responses for this slash command. Usernames can consist of up to 22 characters consisting of lowercase letters, numbers and they symbols \"-\", \"_\", and \".\" .", - "user.settings.cmds.icon_url_desc": "Choose a profile picture override for the post responses to this slash command. Enter the URL of a .png or .jpg file at least 128 pixels by 128 pixels.", - "user.settings.cmds.auto_complete_help": " Show this command in the autocomplete list.", - "user.settings.cmds.auto_complete_hint_desc": "Optional hint in the autocomplete list about parameters needed for command.", - "user.settings.cmds.auto_complete_desc_desc": "Optional short description of slash command for the autocomplete list.", - "user.settings.cmds.cmd_display_name": "Brief description of slash command to show in listings.", - "user.settings.cmds.add": "Add", - "user.settings.hooks_in.channel": "Channel: ", - "user.settings.hooks_in.none": "None", - "user.settings.hooks_in.existing": "Existing incoming webhooks", - "user.settings.hooks_in.description": "Create webhook URLs for use in external integrations. Please see <a href=\"http://docs.mattermost.com/developer/webhooks-incoming.html\" target=\"_blank\">incoming webhooks documentation</a> to learn more.", - "user.settings.hooks_in.addTitle": "Add a new incoming webhook", - "user.settings.hooks_in.add": "Add", - "user.settings.languages.change": "Change interface language", - "user.settings.languages": "Set language", - "user.settings.hooks_out.optional": "Optional if channel selected", - "user.settings.hooks_out.callbackHolder": "Each URL must start with http:// or https://", - "user.settings.hooks_out.select": "--- Select a channel ---", - "user.settings.hooks_out.channel": "Channel: ", - "user.settings.hooks_out.trigger": "Trigger Words: ", - "user.settings.hooks_out.regen": "Regen Token", - "user.settings.hooks_out.none": "None", - "user.settings.hooks_out.existing": "Existing outgoing webhooks", - "user.settings.hooks_out.addDescription": "Create webhooks to send new message events to an external integration. Please see <a href=\"http://docs.mattermost.com/developer/webhooks-outgoing.html\" target=\"_blank\">outgoing webhooks documentation</a> to learn more.", - "user.settings.hooks_out.addTitle": "Add a new outgoing webhook", - "user.settings.hooks_out.only": "Only public channels can be used", - "user.settings.hooks_out.comma": "Comma separated words to trigger on", - "user.settings.hooks_out.callback": "Callback URLs: ", - "user.settings.hooks_out.callbackDesc": "New line separated URLs that will receive the HTTP POST event", - "user.settings.hooks_out.add": "Add", - "user.settings.advance.sendTitle": "Send messages on Ctrl + Enter", - "user.settings.advance.on": "On", - "user.settings.advance.off": "Off", - "user.settings.advance.preReleaseTitle": "Preview pre-release features", - "user.settings.advance.feature": " Feature ", - "user.settings.advance.features": " Features ", - "user.settings.advance.enabled": "enabled", - "user.settings.advance.markdown_preview": "Show markdown preview option in message input box", - "user.settings.advance.embed_preview": "Show preview snippet of links below message", - "user.settings.advance.sendDesc": "If enabled 'Enter' inserts a new line and 'Ctrl + Enter' submits the message.", - "user.settings.advance.preReleaseDesc": "Check any pre-released features you'd like to preview. You may also need to refresh the page before the setting will take effect.", - "user.settings.advance.title": "Advanced Settings", + "user.settings.custom_theme.awayIndicator": "Away Indicator", + "user.settings.custom_theme.buttonBg": "Button BG", + "user.settings.custom_theme.buttonColor": "Button Text", + "user.settings.custom_theme.centerChannelBg": "Center Channel BG", + "user.settings.custom_theme.centerChannelColor": "Center Channel Text", + "user.settings.custom_theme.codeTheme": "Code Theme", + "user.settings.custom_theme.copyPaste": "Copy and paste to share theme colors:", + "user.settings.custom_theme.linkColor": "Link Color", + "user.settings.custom_theme.mentionBj": "Mention Jewel BG", + "user.settings.custom_theme.mentionColor": "Mention Jewel Text", + "user.settings.custom_theme.mentionHighlightBg": "Mention Highlight BG", + "user.settings.custom_theme.mentionHighlightLink": "Mention Highlight Link", + "user.settings.custom_theme.newMessageSeparator": "New Message Separator", + "user.settings.custom_theme.onlineIndicator": "Online Indicator", + "user.settings.custom_theme.sidebarBg": "Sidebar BG", + "user.settings.custom_theme.sidebarHeaderBg": "Sidebar Header BG", + "user.settings.custom_theme.sidebarHeaderTextColor": "Sidebar Header Text", + "user.settings.custom_theme.sidebarText": "Sidebar Text", + "user.settings.custom_theme.sidebarTextActiveBorder": "Sidebar Text Active Border", + "user.settings.custom_theme.sidebarTextActiveColor": "Sidebar Text Active Color", + "user.settings.custom_theme.sidebarTextHoverBg": "Sidebar Text Hover BG", + "user.settings.custom_theme.sidebarUnreadText": "Sidebar Unread Text", "user.settings.developer.applicationsPreview": "Applications (Preview)", - "user.settings.developer.thirdParty": "Open to register a new third-party application", "user.settings.developer.register": "Register New Application", + "user.settings.developer.thirdParty": "Open to register a new third-party application", "user.settings.developer.title": "Developer Settings", - "user.settings.display.normalClock": "12-hour clock (example: 4:00 PM)", - "user.settings.display.militaryClock": "24-hour clock (example: 16:00)", "user.settings.display.clockDisplay": "Clock Display", - "user.settings.display.teammateDisplay": "Teammate Name Display", - "user.settings.display.showNickname": "Show nickname if one exists, otherwise show first and last name", - "user.settings.display.showUsername": "Show username (team default)", - "user.settings.display.showFullname": "Show first and last name", + "user.settings.display.fontDesc": "Select the font displayed in the Mattermost user interface.", "user.settings.display.fontTitle": "Display Font", "user.settings.display.language": "Language", - "user.settings.display.preferTime": "Select how you prefer time displayed.", + "user.settings.display.militaryClock": "24-hour clock (example: 16:00)", "user.settings.display.nameOptsDesc": "Set how to display other user's names in posts and the Direct Messages list.", - "user.settings.display.fontDesc": "Select the font displayed in the Mattermost user interface.", + "user.settings.display.normalClock": "12-hour clock (example: 4:00 PM)", + "user.settings.display.preferTime": "Select how you prefer time displayed.", + "user.settings.display.showFullname": "Show first and last name", + "user.settings.display.showNickname": "Show nickname if one exists, otherwise show first and last name", + "user.settings.display.showUsername": "Show username (team default)", + "user.settings.display.teammateDisplay": "Teammate Name Display", + "user.settings.display.theme.customTheme": "Custom Theme", + "user.settings.display.theme.describe": "Open to manage your theme", + "user.settings.display.theme.import": "Import theme colors from Slack", + "user.settings.display.theme.themeColors": "Theme Colors", + "user.settings.display.theme.title": "Theme", "user.settings.display.title": "Display Settings", - "user.settings.general.usernameReserved": "This username is reserved, please choose a new one.", - "user.settings.general.usernameRestrictions": "'Username must begin with a letter, and contain between {min} to {max} lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'.", - "user.settings.general.validEmail": "Please enter a valid email address", - "user.settings.general.emailMatch": "The new emails you entered do not match.", "user.settings.general.checkEmail": "Check your email at {email} to verify the address.", - "user.settings.general.newAddress": "New Address: {email}<br />Check your email to verify the above address.", "user.settings.general.checkEmailNoAddress": "Check your email to verify your new address", - "user.settings.general.loginGitlab": "Log in done through GitLab", - "user.settings.general.validImage": "Only JPG or PNG images may be used for profile pictures", - "user.settings.general.imageTooLarge": "Unable to upload profile image. File is too large.", - "user.settings.general.uploadImage": "Click 'Edit' to upload an image.", - "user.settings.general.imageUpdated": "Image last updated {date}", - "user.settings.general.fullName": "Full Name", - "user.settings.general.nickname": "Nickname", - "user.settings.general.username": "Username", - "user.settings.general.email": "Email", - "user.settings.general.profilePicture": "Profile Picture", "user.settings.general.close": "Close", - "user.settings.general.firstName": "First Name", - "user.settings.general.lastName": "Last Name", - "user.settings.general.notificationsLink": "Notifications", - "user.settings.general.notificationsExtra": "By default, you will receive mention notifications when someone types your first name. Go to {notify} settings to change this default.", - "user.settings.general.nicknameExtra": "Use Nickname for a name you might be called that is different from your first name and username. This is most often used when two or more people have similar sounding names and usernames.", - "user.settings.general.usernameInfo": "Pick something easy for teammates to recognize and recall.", + "user.settings.general.confirmEmail": "Confirm Email", + "user.settings.general.email": "Email", + "user.settings.general.emailCantUpdate": "Log in occurs through GitLab. Email cannot be updated.", "user.settings.general.emailHelp1": "Email is used for sign-in, notifications, and password reset. Email requires verification if changed.", "user.settings.general.emailHelp2": "Email has been disabled by your system administrator. No notification emails will be sent until it is enabled.", "user.settings.general.emailHelp3": "Email is used for sign-in, notifications, and password reset.", "user.settings.general.emailHelp4": "A verification email was sent to {email}.", + "user.settings.general.emailMatch": "The new emails you entered do not match.", + "user.settings.general.firstName": "First Name", + "user.settings.general.fullName": "Full Name", + "user.settings.general.imageTooLarge": "Unable to upload profile image. File is too large.", + "user.settings.general.imageUpdated": "Image last updated {date}", + "user.settings.general.lastName": "Last Name", + "user.settings.general.loginGitlab": "Log in done through GitLab", + "user.settings.general.newAddress": "New Address: {email}<br />Check your email to verify the above address.", + "user.settings.general.nickname": "Nickname", + "user.settings.general.nicknameExtra": "Use Nickname for a name you might be called that is different from your first name and username. This is most often used when two or more people have similar sounding names and usernames.", + "user.settings.general.notificationsExtra": "By default, you will receive mention notifications when someone types your first name. Go to {notify} settings to change this default.", + "user.settings.general.notificationsLink": "Notifications", "user.settings.general.primaryEmail": "Primary Email", - "user.settings.general.confirmEmail": "Confirm Email", - "user.settings.general.emailCantUpdate": "Log in occurs through GitLab. Email cannot be updated.", + "user.settings.general.profilePicture": "Profile Picture", "user.settings.general.title": "General Settings", + "user.settings.general.uploadImage": "Click 'Edit' to upload an image.", + "user.settings.general.username": "Username", + "user.settings.general.usernameInfo": "Pick something easy for teammates to recognize and recall.", + "user.settings.general.usernameReserved": "This username is reserved, please choose a new one.", + "user.settings.general.usernameRestrictions": "Username must begin with a letter, and contain between {min} to {max} lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'.", + "user.settings.general.validEmail": "Please enter a valid email address", + "user.settings.general.validImage": "Only JPG or PNG images may be used for profile pictures", + "user.settings.hooks_in.add": "Add", + "user.settings.hooks_in.addTitle": "Add a new incoming webhook", + "user.settings.hooks_in.channel": "Channel: ", + "user.settings.hooks_in.description": "Create webhook URLs for use in external integrations. Please see <a href=\"http://docs.mattermost.com/developer/webhooks-incoming.html\" target=\"_blank\">incoming webhooks documentation</a> to learn more.", + "user.settings.hooks_in.existing": "Existing incoming webhooks", + "user.settings.hooks_in.none": "None", + "user.settings.hooks_out.add": "Add", + "user.settings.hooks_out.addDescription": "Create webhooks to send new message events to an external integration. Please see <a href=\"http://docs.mattermost.com/developer/webhooks-outgoing.html\" target=\"_blank\">outgoing webhooks documentation</a> to learn more.", + "user.settings.hooks_out.addTitle": "Add a new outgoing webhook", + "user.settings.hooks_out.callback": "Callback URLs: ", + "user.settings.hooks_out.callbackDesc": "New line separated URLs that will receive the HTTP POST event", + "user.settings.hooks_out.callbackHolder": "Each URL must start with http:// or https://", + "user.settings.hooks_out.channel": "Channel: ", + "user.settings.hooks_out.comma": "Comma separated words to trigger on", + "user.settings.hooks_out.existing": "Existing outgoing webhooks", + "user.settings.hooks_out.none": "None", + "user.settings.hooks_out.only": "Only public channels can be used", + "user.settings.hooks_out.optional": "Optional if channel selected", + "user.settings.hooks_out.regen": "Regen Token", + "user.settings.hooks_out.select": "--- Select a channel ---", + "user.settings.hooks_out.trigger": "Trigger Words: ", + "user.settings.import_theme.cancel": "Cancel", + "user.settings.import_theme.importBody": "To import a theme, go to a Slack team and look for “Preferences -> Sidebar Theme”. Open the custom theme option, copy the theme color values and paste them here:", + "user.settings.import_theme.importHeader": "Import Slack Theme", + "user.settings.import_theme.submit": "Submit", + "user.settings.import_theme.submitError": "Invalid format, please try copying and pasting in again.", + "user.settings.integrations.commands": "Slash Commands", + "user.settings.integrations.commandsDescription": "Manage your slash commands", "user.settings.integrations.incomingWebhooks": "Incoming Webhooks", "user.settings.integrations.incomingWebhooksDescription": "Manage your incoming webhooks", "user.settings.integrations.outWebhooks": "Outgoing Webhooks", "user.settings.integrations.outWebhooksDescription": "Manage your outgoing webhooks", - "user.settings.integrations.commands": "Slash Commands", - "user.settings.integrations.commandsDescription": "Manage your slash commands", "user.settings.integrations.title": "Integration Settings", - "user.settings.modal.general": "General", - "user.settings.modal.security": "Security", - "user.settings.modal.notifications": "Notifications", - "user.settings.modal.developer": "Developer", - "user.settings.modal.integrations": "Integrations", - "user.settings.modal.display": "Display", + "user.settings.languages": "Set language", + "user.settings.languages.change": "Change interface language", "user.settings.modal.advanced": "Advanced", - "user.settings.modal.confirmTitle": "Discard Changes?", - "user.settings.modal.confirmMsg": "You have unsaved changes, are you sure you want to discard them?", "user.settings.modal.confirmBtns": "Yes, Discard", + "user.settings.modal.confirmMsg": "You have unsaved changes, are you sure you want to discard them?", + "user.settings.modal.confirmTitle": "Discard Changes?", + "user.settings.modal.developer": "Developer", + "user.settings.modal.display": "Display", + "user.settings.modal.general": "General", + "user.settings.modal.integrations": "Integrations", + "user.settings.modal.notifications": "Notifications", + "user.settings.modal.security": "Security", "user.settings.modal.title": "Account Settings", + "user.settings.notification.allActivity": "For all activity", + "user.settings.notification.soundConfig": "Please configure notification sounds in your browser settings", + "user.settings.notifications.channelWide": "Channel-wide mentions \"@channel\"", + "user.settings.notifications.close": "Close", "user.settings.notifications.desktop": "Send desktop notifications", "user.settings.notifications.desktopSounds": "Desktop notification sounds", + "user.settings.notifications.emailInfo": "Email notifications are sent for mentions and direct messages after you’ve been offline for more than 60 seconds or away from {siteName} for more than 5 minutes.", "user.settings.notifications.emailNotifications": "Email notifications", - "user.settings.notifications.wordsTrigger": "Words that trigger mentions", - "user.settings.notifications.close": "Close", - "user.settings.notification.allActivity": "For all activity", - "user.settings.notifications.onlyMentions": "Only for mentions and direct messages", - "user.settings.notifications.never": "Never", + "user.settings.notifications.header": "Notifications", "user.settings.notifications.info": "Desktop notifications are available on Firefox, Safari, Chrome, Internet Explorer, and Edge.", - "user.settings.notifications.on": "On", + "user.settings.notifications.never": "Never", + "user.settings.notifications.noWords": "No words configured", "user.settings.notifications.off": "Off", - "user.settings.notifications.sounds_info": "Desktop notifications sounds are available on Firefox, Safari, Chrome, Internet Explorer, and Edge.", - "user.settings.notification.soundConfig": "Please configure notification sounds in your browser settings", - "user.settings.notifications.emailInfo": "Email notifications are sent for mentions and direct messages after you’ve been offline for more than 60 seconds or away from {siteName} for more than 5 minutes.", + "user.settings.notifications.on": "On", + "user.settings.notifications.onlyMentions": "Only for mentions and direct messages", "user.settings.notifications.sensitiveName": "Your case sensitive first name \"{first_name}\"", "user.settings.notifications.sensitiveUsername": "Your non-case sensitive username \"{username}\"", - "user.settings.notifications.usernameMention": "Your username mentioned \"@{username}\"", - "user.settings.notifications.teamWide": "Team-wide mentions \"@all\"", - "user.settings.notifications.channelWide": "Channel-wide mentions \"@channel\"", "user.settings.notifications.sensitiveWords": "Other non-case sensitive words, separated by commas:", - "user.settings.notifications.noWords": "No words configured", + "user.settings.notifications.sounds_info": "Desktop notifications sounds are available on Firefox, Safari, Chrome, Internet Explorer, and Edge.", + "user.settings.notifications.teamWide": "Team-wide mentions \"@all\"", "user.settings.notifications.title": "Notification Settings", - "user.settings.notifications.header": "Notifications", + "user.settings.notifications.usernameMention": "Your username mentioned \"@{username}\"", + "user.settings.notifications.wordsTrigger": "Words that trigger mentions", + "user.settings.security.close": "Close", + "user.settings.security.currentPassword": "Current Password", "user.settings.security.currentPasswordError": "Please enter your current password", - "user.settings.security.passwordLengthError": "New passwords must be at least {chars} characters", - "user.settings.security.passwordMatchError": "The new passwords you entered do not match", - "user.settings.security.password": "Password", + "user.settings.security.emailPwd": "Email and Password", + "user.settings.security.gitlab": "GitLab SSO", "user.settings.security.lastUpdated": "Last updated {date} at {time}", + "user.settings.security.logoutActiveSessions": "View and Logout of Active Sessions", "user.settings.security.method": "Sign-in Method", - "user.settings.security.close": "Close", - "user.settings.security.currentPassword": "Current Password", "user.settings.security.newPassword": "New Password", + "user.settings.security.oneSignin": "You may only have one sign-in method at a time. Switching sign-in method will send an email notifying you if the change was successful.", + "user.settings.security.password": "Password", + "user.settings.security.passwordLengthError": "New passwords must be at least {chars} characters", + "user.settings.security.passwordMatchError": "The new passwords you entered do not match", "user.settings.security.retypePassword": "Retype New Password", "user.settings.security.switchEmail": "Switch to using email and password", "user.settings.security.switchGitlab": "Switch to using GitLab SSO", "user.settings.security.switchGoogle": "Switch to using Google SSO", - "user.settings.security.oneSignin": "You may only have one sign-in method at a time. Switching sign-in method will send an email notifying you if the change was successful.", - "user.settings.security.emailPwd": "Email and Password", - "user.settings.security.gitlab": "GitLab SSO", "user.settings.security.title": "Security Settings", "user.settings.security.viewHistory": "View Access History", - "user.settings.security.logoutActiveSessions": "View and Logout of Active Sessions", - "user.settings.display.theme.title": "Theme", - "user.settings.display.theme.describe": "Open to manage your theme", - "user.settings.display.theme.themeColors": "Theme Colors", - "user.settings.display.theme.customTheme": "Custom Theme", - "user.settings.display.theme.import": "Import theme colors from Slack", - "view_image_popover.publicLink": "Get Public Link", - "view_image_popover.file": "File {count} of {total}", - "view_image_popover.download": "Download", + "user_profile.notShared": "Email not shared", "view_image.loading": "Loading ", - "intro_messages.DM": "This is the start of your direct message history with {teammate}.<br />Direct messages and files shared here are not shown to people outside this area.", - "intro_messages.teammate": "This is the start of your direct message history with this teammate. Direct messages and files shared here are not shown to people outside this area.", - "intro_messages.offTopic": "<h4 class=\"channel-intro__title\">Beginning of {display_name}</h4><p class=\"channel-intro__content\">This is the start of {display_name}, a channel for non-work-related conversations.<br/></p>", - "intro_messages.inviteOthers": "Invite others to this team", - "intro_messages.default": "<h4 class='channel-intro__title'>Beginning of {display_name}</h4><p class='channel-intro__content'><strong>Welcome to {display_name}!</strong><br/><br/>This is the first channel teammates see when they sign up - use it for posting updates everyone needs to know.</p>", - "intro_messages.group": "private group", - "intro_messages.onlyInvited": " Only invited members can see this private group.", - "intro_messages.channel": "channel", - "intro_messages.anyMember": " Any member can join and read this channel.", - "intro_messages.noCreator": "This is the start of the {name} {type}, created on {date}.", - "intro_messages.creator": "This is the start of the <strong>{name}</strong> {type}, created by <strong>{creator}</strong> on <strong>{date}</strong>", - "intro_messages.beginning": "Beginning of {name}", - "intro_messages.invite": "Invite others to this {type}", - "intro_messages.setHeader": "Set a Header" + "view_image_popover.download": "Download", + "view_image_popover.file": "File {count} of {total}", + "view_image_popover.publicLink": "Get Public Link" } diff --git a/web/static/i18n/es.json b/web/static/i18n/es.json index 5723bd171..f0fec290a 100644 --- a/web/static/i18n/es.json +++ b/web/static/i18n/es.json @@ -67,7 +67,7 @@ "admin.email.notificationEmailDescription": "La dirección de correo electrónico a mostrar en la cuenta de correo utilizada cuando se envian notificaciones por correo electrónico desde Mattermost.", "admin.email.notificationEmailExample": "Ej: \"mattermost@tuempresa.com\", \"admin@tuempresa.com\"", "admin.email.notificationEmailTitle": "Notificación de correo electrónico:", - "admin.email.notificationsDescription": "Normalmente se asigna como verdadero en producción. Cuando es verdadero, Mattermost intenta enviar las notificaciones por correo electrónico. Los desarrolladores puede que quieran dejar esta opción en falso para saltarse la configuración de correos para desarrollar más rápido.\nAsignar está opción como verdadero remueve la notificación de Modo de Prueba (requiere cerrar la sesión y abrirla nuevamente para que los cambios surjan efecto).", + "admin.email.notificationsDescription": "Normalmente se asigna como verdadero en producción. Cuando es verdadero, Mattermost intenta enviar las notificaciones por correo electrónico. Los desarrolladores puede que quieran dejar esta opción en falso para saltarse la configuración de correos para desarrollar más rápido.<br/>Asignar está opción como verdadero remueve la notificación de Modo de Prueba (requiere cerrar la sesión y abrirla nuevamente para que los cambios surjan efecto).", "admin.email.notificationsTitle": "Enviar notificaciones por correo electrónico: ", "admin.email.passwordSaltDescription": "Un salt de 32-caracteres es añadido a la firma de correos para restablecer la contraseña. Aleatoriamente generado en la instalación. Pincha \"Regenerar\" para crear un nuevo salt.", "admin.email.passwordSaltExample": "Ej \"bjlSR4QqkXFBr7TP4oDzlfZmcNuH9Yo\"", @@ -106,7 +106,7 @@ "admin.gitlab.clientIdTitle": "Id:", "admin.gitlab.clientSecretExample": "Ej \"jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY\"", "admin.gitlab.clientSecretTitle": "Secreto:", - "admin.gitlab.enableDescription": "Cuando está asignado como verdadero, Mattermost permite la creación de equipos y cuentas utilizando el servicio de OAuth de GitLab. Para configurarlo, inicia sesión en GitLab con tu cuenta y dirigete a Applications -> Profile Settings. Ingresa los URIs de redireccionamiento \"<tu-mattermost-url>/login/gitlab/complete\" (ejemplo: http://localhost:8065/login/gitlab/complete) y \"<tu-mattermost-url>/signup/gitlab/complete\". Luego utiliza los campos de \"Secret\" y \"Id\" para completar las opciones de abajo.", + "admin.gitlab.enableDescription": "Cuando está asignado como verdadero, Mattermost permite la creación de equipos y cuentas utilizando el servicio de OAuth de GitLab.", "admin.gitlab.enableTitle": "Enable Sign Up With GitLab: ", "admin.gitlab.false": "falso", "admin.gitlab.save": "Guardar", @@ -116,7 +116,7 @@ "admin.gitlab.tokenExample": "Ej \"\"", "admin.gitlab.tokenTitle": "Url para obteción de Token:", "admin.gitlab.true": "verdadero", - "admin.gitlab.userDescription": "Ingresar <tu-gitlab-url>/api/v3/user. Asegurate que si utilizas HTTPS o HTTPS tus URLS sean correctas", + "admin.gitlab.userDescription": "Ingresar <tu-gitlab-url>/api/v3/user. Asegurate que si utilizas HTTPS o HTTPS tus URLS sean correctas", "admin.gitlab.userExample": "Ej \"\"", "admin.gitlab.userTitle": "URL para obtener datos de usuario:", "admin.image.amazonS3BucketDescription": "Nombre que ha seleccionado para el bucket S3 en AWS.", @@ -190,7 +190,7 @@ "admin.ldap.lastnameAttrDesc": "El atributo en el servidor LDAP que será utilizado para poblar el apellido de los usuarios en Mattermost.", "admin.ldap.lastnameAttrEx": "Ej \"sn\"", "admin.ldap.lastnameAttrTitle": "Atributo Apellido:", - "admin.ldap.noLicense": "<h4 className=\"banner__heading\">Nota:</h4><p>LDAP es una característica de la edición enterprise. Tu licencia actual no soporta LDAP. Pincha <a href=\"http://mattermost.com\"target=\"_blank\">aquí</a> para información y precios de las licencias enterprise.</p>", + "admin.ldap.noLicense": "<h4 class=\"banner__heading\">Nota:</h4><p>LDAP es una característica de la edición enterprise. Tu licencia actual no soporta LDAP. Pincha <a href=\"http://mattermost.com\" target=\"_blank\">aquí</a> para información y precios de las licencias enterprise.</p>", "admin.ldap.portDesc": "El puerto que Mattermost utilizará para conectarse al servidor LDAP. El predeterminado es 389.", "admin.ldap.portEx": "Ej \"389\"", "admin.ldap.portTitle": "Puerto LDAP:", @@ -425,7 +425,7 @@ "admin.team.userCreationTitle": "Habilitar Creación de Usuarios: ", "admin.team_analytics.activeUsers": "Active Users With Posts", "admin.team_analytics.totalPosts": "Total de Mensajes", - "admin.userList.title": "Usuarios para ", + "admin.userList.title": "Usuarios para {team}", "admin.userList.title2": "Usuarios para {team} ({count})", "admin.user_item.confirmDemoteDescription": "Si te degradas a ti mismo de la función de Administrador de Sistema y no hay otro usuario con privilegios de Administrador de Sistema, tendrás que volver a asignar un Administrador del Sistema accediendo al servidor de Mattermost a través de un terminal y ejecutar el siguiente comando.", "admin.user_item.confirmDemoteRoleTitle": "Confirmar el decenso del rol de Administrador de Sistema", @@ -466,7 +466,7 @@ "audit_table.failedWebhookCreate": "Falla al crear un webhook - no tiene permisos en el canal", "audit_table.failedWebhookDelete": "Falla al borrar un webhook - condiciones inapropiadas", "audit_table.headerUpdated": "Actualizado el encabezado del canal/grupo {channelName}", - "audit_table.ip": "IP: {ip}", + "audit_table.ip": "Dirección IP", "audit_table.licenseRemoved": "Licencia eliminada con éxito", "audit_table.loginAttempt": " (intento de inicio de sesión)", "audit_table.loginFailure": " (inicio de sesión fallido)", @@ -476,7 +476,7 @@ "audit_table.oauthTokenFailed": "Falla al obtener un token de acceso de OAuth - {token}", "audit_table.revokedAll": "Revocadas todas las sesiones actuales del equipo", "audit_table.sentEmail": "Correo electrónico enviado a {email} para restablecer tu contraseña", - "audit_table.session": "ID de Sesión: {id}", + "audit_table.session": "ID de sesión", "audit_table.sessionRevoked": "La sesión con id {sessionId} fue revocada", "audit_table.successfullLicenseAdd": "Licencia agregada con éxito", "audit_table.successfullLogin": "Inicio de sesión satisfactorio", @@ -495,9 +495,9 @@ "audit_table.userId": "ID de Usuario", "audit_table.userRemoved": "Removido {username} del canal/grupo {channelName}", "audit_table.verified": "Verificada la dirección de correo electrónico satisfacoriamente", - "authorize.access": "¿Permitir acceso a {appName}?", + "authorize.access": "¿Permitir acceso a <strong>{appName}</strong>?", "authorize.allow": "Permitir", - "authorize.app": "La app {appName} quiere tener la abilidad de accesar y modificar tu información básica.", + "authorize.app": "La app <strong>{appName}</strong> quiere tener la habilidad de accesar y modificar tu información básica.", "authorize.deny": "Denegar", "authorize.title": "Una aplicación quiere conectarse con tu cuenta de {teamName}", "center_panel.recent": "Pincha aquí para ir a los mensajes más recientes. ", @@ -520,11 +520,11 @@ "channel_header.channelHeader": "Asignar Encabezado del Canal...", "channel_header.delete": "Borrar {term}...", "channel_header.group": "Grupo", - "channel_header.leave": "Abandonar ", + "channel_header.leave": "Abandonar {term}", "channel_header.manageMembers": "Administrar Miembros", "channel_header.notificationPreferences": "Preferencias de Notificación", "channel_header.recentMentions": "Menciones recientes", - "channel_header.rename": "Renombrar ", + "channel_header.rename": "Renombrar {term}...", "channel_header.setHeader": "Encabezado del {term}...", "channel_header.setPurpose": "Propósito del {term}...", "channel_header.viewInfo": "Ver Info", @@ -564,7 +564,7 @@ "channel_modal.purpose": "Propósito", "channel_notifications.allActivity": "Para toda actividad", "channel_notifications.allUnread": "Para todos los mensajes sin leer", - "channel_notifications.globalDefault": "Predeterminada", + "channel_notifications.globalDefault": "Predeterminada ({notifyLevel})", "channel_notifications.markUnread": "Marcar Canal como No Leido", "channel_notifications.never": "Nunca", "channel_notifications.onlyMentions": "Sólo para menciones", @@ -609,7 +609,7 @@ "delete_channel.confirm": "Confirmar BORRAR Canal", "delete_channel.del": "Borrar", "delete_channel.group": "grupo", - "delete_channel.question": "¿Estás seguro de querer borrar el ", + "delete_channel.question": "¿Estás seguro de querer borrar el {display_name} {term}?", "delete_post.cancel": "Cancelar", "delete_post.comment": "Comentario", "delete_post.confirm": "Confirmar Eliminación del {term}", @@ -811,7 +811,7 @@ "navbar_dropdown.teamSettings": "Configurar Equipo", "password_form.change": "Cambiar mi contraseña", "password_form.click": " Pincha <a href={url}>aquí</a> para iniciar sesión.", - "password_form.enter": "Ingresa una nueva contraseña para tu cuenta en {teamDisplayName} {SiteName}.", + "password_form.enter": "Ingresa una nueva contraseña para tu cuenta en {teamDisplayName} {siteName}.", "password_form.error": "Por favor ingresa al menos {chars} caracteres.", "password_form.pwd": "Contraseña", "password_form.title": "Restablecer Contraseña", @@ -865,7 +865,6 @@ "removed_channel.remover": "{remover} te removió de {channel}", "removed_channel.someone": "Alguien", "rename_channel.cancel": "Cancelar", - "rename_channel.close": "Cerrado", "rename_channel.defaultError": " - No se puede cambiar el del canal predeterminado", "rename_channel.displayName": "Nombre a Mostrar", "rename_channel.displayNameHolder": "Ingresa el nombre a mostrar", @@ -893,7 +892,7 @@ "search_header.title2": "Menciones Recientes", "search_item.direct": "Mensjae Directo", "search_item.jump": "Ir ", - "search_results.because": "<ul><li>Si estás buscando un frase parcial (ej. buscando \"aud\", tratando de encontrar \"audible\" o \"audifonos\"), agrega un * a la palabra que estás buscando</li><li>Debido a la cantidad de resultados, la búsqueda con dos letras y palabras comunes como \"this\", \"a\" and \"es\" no aparecerán en los resultados</li>/ul>", + "search_results.because": "<ul><li>Si estás buscando un frase parcial (ej. buscando \"aud\", tratando de encontrar \"audible\" o \"audifonos\"), agrega un * a la palabra que estás buscando</li><li>Debido a la cantidad de resultados, la búsqueda con dos letras y palabras comunes como \"this\", \"a\" and \"es\" no aparecerán en los resultados</li></ul>", "search_results.noResults": "SIN RESULTADOS", "search_results.usage": "<ul><li>Utiliza <b>\"comillas\"</b> para buscar frases</li><li>Utiliza <b>from:</b> para encontrar mensajes de usuarios en específico e <b>in:</b> para encontrar mensajes de canales específicos</li></ul>", "setting_item_max.cancel": "Cancelar", @@ -915,7 +914,7 @@ "sidebar.pg": "Grupos Privados", "sidebar.removeList": "Remover de la lista", "sidebar.tutorialScreen1": "<h4>Canales</h4><p><strong>Canales</strong> organizan las conversaciones en diferentes tópicos. Son abiertos para cualquier persona de tu equipo. Para enviar comunicaciones privadas con una sola persona utiliza <strong>Mensajes Directos</strong> o con multiples personas utilizando <strong>Grupos Privados</strong>.</p>", - "sidebar.tutorialScreen2": "<h4>Canal \"General\"</h4><p>Este es un canal para comenzar:</p><p><strong>General</strong> es el lugar para tener comunicación con todo el equipo. Todos los integrantes de tu equipo son miembros de este canal.</p>", + "sidebar.tutorialScreen2": "<h4>Los canal \"General\" y \"Fuera de Tópico\"</h4><p>Estos son dos canales para comenzar:</p><p><strong>General</strong> es el lugar para tener comunicación con todo el equipo. Todos los integrantes de tu equipo son miembros de este canal.</p><p><strong>Fuera de Tópico</strong> es un lugar para diversión y humor fuera de los canales relacionados con el trabajo. Tu y tu equipo pueden decidir que otros canales crear.</p>", "sidebar.tutorialScreen3": "<h4>Creando y Uniendose a Canales</h4><p>Pincha en <strong>\"Más...\"</strong> para crear un nuevo canal o unirte a uno existente.</p><p>También puedes crear un nuevo canal o grupo privado al pinchar el simbolo de <strong>\"+\"</strong> que se encuentra al lado del encabezado de Canales o Grupos Privados.</p>", "sidebar.unreadAbove": "Mensaje(s) sin leer ▲", "sidebar.unreadBelow": "Mensaje(s) sin leer ▼", @@ -1185,7 +1184,7 @@ "user.settings.hooks_in.add": "Agregar", "user.settings.hooks_in.addTitle": "Agregar un nuevo webhook de entrada", "user.settings.hooks_in.channel": "Canal: ", - "user.settings.hooks_in.description": "Crea webhooks URLs para utilizarlos con integraciones externas. Por favor revisa <a href=\"http://docs.mattermost.com/developer/webhooks-incoming.html\" target=\"_blank\">documentación de webhook de entrada</a> para aprender más.", + "user.settings.hooks_in.description": "Crea webhooks URLs para utilizarlos con integraciones externas. Por favor revisa <a href=\"http://docs.mattermost.com/developer/webhooks-incoming.html\" target=\"_blank\">documentación de webhook de entrada</a> para conocer más.", "user.settings.hooks_in.existing": "Webhooks de entrada existentes", "user.settings.hooks_in.none": "Ninguno", "user.settings.hooks_out.add": "Agregar", diff --git a/web/static/js/perfect-scrollbar-0.6.7.jquery.js b/web/static/js/perfect-scrollbar-0.6.10.jquery.js index 6c25fa91f..fbfd4796e 100644 --- a/web/static/js/perfect-scrollbar-0.6.7.jquery.js +++ b/web/static/js/perfect-scrollbar-0.6.10.jquery.js @@ -1,8 +1,5 @@ -/* perfect-scrollbar v0.6.7 */ +/* perfect-scrollbar v0.6.10 */ (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ 'use strict'; var ps = require('../main') @@ -48,9 +45,6 @@ if (typeof define === 'function' && define.amd) { module.exports = mountJQuery; },{"../main":7,"../plugin/instances":18}],2:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ 'use strict'; function oldAdd(element, className) { @@ -95,9 +89,6 @@ exports.list = function (element) { }; },{}],3:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ 'use strict'; var DOM = {}; @@ -184,9 +175,6 @@ DOM.queryChildren = function (element, selector) { module.exports = DOM; },{}],4:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ 'use strict'; var EventElement = function (element) { @@ -260,9 +248,6 @@ EventManager.prototype.once = function (element, eventName, handler) { module.exports = EventManager; },{}],5:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ 'use strict'; module.exports = (function () { @@ -278,9 +263,6 @@ module.exports = (function () { })(); },{}],6:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ 'use strict'; var cls = require('./class') @@ -364,9 +346,6 @@ exports.env = { }; },{"./class":2,"./dom":3}],7:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ 'use strict'; var destroy = require('./plugin/destroy') @@ -380,9 +359,6 @@ module.exports = { }; },{"./plugin/destroy":9,"./plugin/initialize":17,"./plugin/update":21}],8:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ 'use strict'; module.exports = { @@ -398,13 +374,11 @@ module.exports = { useKeyboard: true, useSelectionScroll: false, wheelPropagation: false, - wheelSpeed: 1 + wheelSpeed: 1, + theme: 'default' }; },{}],9:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ 'use strict'; var d = require('../lib/dom') @@ -429,9 +403,6 @@ module.exports = function (element) { }; },{"../lib/dom":3,"../lib/helper":6,"./instances":18}],10:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ 'use strict'; var h = require('../../lib/helper') @@ -451,7 +422,7 @@ function bindClickRailHandler(element, i) { } i.event.bind(i.scrollbarYRail, 'click', function (e) { var halfOfScrollbarLength = h.toInt(i.scrollbarYHeight / 2); - var positionTop = i.railYRatio * (e.pageY - window.scrollY - pageOffset(i.scrollbarYRail).top - halfOfScrollbarLength); + var positionTop = i.railYRatio * (e.pageY - window.pageYOffset - pageOffset(i.scrollbarYRail).top - halfOfScrollbarLength); var maxPositionTop = i.railYRatio * (i.railYHeight - i.scrollbarYHeight); var positionRatio = positionTop / maxPositionTop; @@ -474,7 +445,7 @@ function bindClickRailHandler(element, i) { } i.event.bind(i.scrollbarXRail, 'click', function (e) { var halfOfScrollbarLength = h.toInt(i.scrollbarXWidth / 2); - var positionLeft = i.railXRatio * (e.pageX - window.scrollX - pageOffset(i.scrollbarXRail).left - halfOfScrollbarLength); + var positionLeft = i.railXRatio * (e.pageX - window.pageXOffset - pageOffset(i.scrollbarXRail).left - halfOfScrollbarLength); var maxPositionLeft = i.railXRatio * (i.railXWidth - i.scrollbarXWidth); var positionRatio = positionLeft / maxPositionLeft; @@ -497,9 +468,6 @@ module.exports = function (element) { }; },{"../../lib/helper":6,"../instances":18,"../update-geometry":19,"../update-scroll":20}],11:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ 'use strict'; var d = require('../../lib/dom') @@ -514,7 +482,7 @@ function bindMouseScrollXHandler(element, i) { function updateScrollLeft(deltaX) { var newLeft = currentLeft + (deltaX * i.railXRatio); - var maxLeft = i.scrollbarXRail.getBoundingClientRect().left + (i.railXRatio * (i.railXWidth - i.scrollbarXWidth)); + var maxLeft = Math.max(0, i.scrollbarXRail.getBoundingClientRect().left) + (i.railXRatio * (i.railXWidth - i.scrollbarXWidth)); if (newLeft < 0) { i.scrollbarXLeft = 0; @@ -559,7 +527,7 @@ function bindMouseScrollYHandler(element, i) { function updateScrollTop(deltaY) { var newTop = currentTop + (deltaY * i.railYRatio); - var maxTop = i.scrollbarYRail.getBoundingClientRect().top + (i.railYRatio * (i.railYHeight - i.scrollbarYHeight)); + var maxTop = Math.max(0, i.scrollbarYRail.getBoundingClientRect().top) + (i.railYRatio * (i.railYHeight - i.scrollbarYHeight)); if (newTop < 0) { i.scrollbarYTop = 0; @@ -605,12 +573,10 @@ module.exports = function (element) { }; },{"../../lib/dom":3,"../../lib/helper":6,"../instances":18,"../update-geometry":19,"../update-scroll":20}],12:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ 'use strict'; var h = require('../../lib/helper') + , d = require('../../lib/dom') , instances = require('../instances') , updateGeometry = require('../update-geometry') , updateScroll = require('../update-scroll'); @@ -653,7 +619,10 @@ function bindKeyboardHandler(element, i) { return; } - if (!hovered) { + var focused = d.matches(i.scrollbarX, ':focus') || + d.matches(i.scrollbarY, ':focus'); + + if (!hovered && !focused) { return; } @@ -731,14 +700,10 @@ module.exports = function (element) { bindKeyboardHandler(element, i); }; -},{"../../lib/helper":6,"../instances":18,"../update-geometry":19,"../update-scroll":20}],13:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ +},{"../../lib/dom":3,"../../lib/helper":6,"../instances":18,"../update-geometry":19,"../update-scroll":20}],13:[function(require,module,exports){ 'use strict'; -var h = require('../../lib/helper') - , instances = require('../instances') +var instances = require('../instances') , updateGeometry = require('../update-geometry') , updateScroll = require('../update-scroll'); @@ -815,13 +780,6 @@ function bindMouseWheelHandler(element, i) { } function mousewheelHandler(e) { - // FIXME: this is a quick fix for the select problem in FF and IE. - // If there comes an effective way to deal with the problem, - // this lines should be removed. - if (!h.env.isWebKit && element.querySelector('select:focus')) { - return; - } - var delta = getDeltaFromEvent(e); var deltaX = delta[0]; @@ -878,10 +836,7 @@ module.exports = function (element) { bindMouseWheelHandler(element, i); }; -},{"../../lib/helper":6,"../instances":18,"../update-geometry":19,"../update-scroll":20}],14:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ +},{"../instances":18,"../update-geometry":19,"../update-scroll":20}],14:[function(require,module,exports){ 'use strict'; var instances = require('../instances') @@ -899,9 +854,6 @@ module.exports = function (element) { }; },{"../instances":18,"../update-geometry":19}],15:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ 'use strict'; var h = require('../../lib/helper') @@ -1013,9 +965,6 @@ module.exports = function (element) { }; },{"../../lib/helper":6,"../instances":18,"../update-geometry":19,"../update-scroll":20}],16:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ 'use strict'; var instances = require('../instances') @@ -1186,9 +1135,6 @@ module.exports = function (element, supportsTouch, supportsIePointer) { }; },{"../instances":18,"../update-geometry":19,"../update-scroll":20}],17:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ 'use strict'; var cls = require('../lib/class') @@ -1214,6 +1160,7 @@ module.exports = function (element, userSettings) { var i = instances.add(element); i.settings = h.extend(i.settings, userSettings); + cls.add(element, 'ps-theme-' + i.settings.theme); clickRailHandler(element); dragScrollbarHandler(element); @@ -1235,12 +1182,10 @@ module.exports = function (element, userSettings) { }; },{"../lib/class":2,"../lib/helper":6,"./handler/click-rail":10,"./handler/drag-scrollbar":11,"./handler/keyboard":12,"./handler/mouse-wheel":13,"./handler/native-scroll":14,"./handler/selection":15,"./handler/touch":16,"./instances":18,"./update-geometry":19}],18:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ 'use strict'; -var d = require('../lib/dom') +var cls = require('../lib/class') + , d = require('../lib/dom') , defaultSettings = require('./default-setting') , EventManager = require('../lib/event-manager') , guid = require('../lib/guid') @@ -1270,8 +1215,19 @@ function Instance(element) { i.event = new EventManager(); i.ownerDocument = element.ownerDocument || document; + function focus() { + cls.add(element, 'ps-focus'); + } + + function blur() { + cls.remove(element, 'ps-focus'); + } + i.scrollbarXRail = d.appendTo(d.e('div', 'ps-scrollbar-x-rail'), element); i.scrollbarX = d.appendTo(d.e('div', 'ps-scrollbar-x'), i.scrollbarXRail); + i.scrollbarX.setAttribute('tabindex', 0); + i.event.bind(i.scrollbarX, 'focus', focus); + i.event.bind(i.scrollbarX, 'blur', blur); i.scrollbarXActive = null; i.scrollbarXWidth = null; i.scrollbarXLeft = null; @@ -1288,6 +1244,9 @@ function Instance(element) { i.scrollbarYRail = d.appendTo(d.e('div', 'ps-scrollbar-y-rail'), element); i.scrollbarY = d.appendTo(d.e('div', 'ps-scrollbar-y'), i.scrollbarYRail); + i.scrollbarY.setAttribute('tabindex', 0); + i.event.bind(i.scrollbarY, 'focus', focus); + i.event.bind(i.scrollbarY, 'blur', blur); i.scrollbarYActive = null; i.scrollbarYHeight = null; i.scrollbarYTop = null; @@ -1343,10 +1302,7 @@ exports.get = function (element) { return instances[getId(element)]; }; -},{"../lib/dom":3,"../lib/event-manager":4,"../lib/guid":5,"../lib/helper":6,"./default-setting":8}],19:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ +},{"../lib/class":2,"../lib/dom":3,"../lib/event-manager":4,"../lib/guid":5,"../lib/helper":6,"./default-setting":8}],19:[function(require,module,exports){ 'use strict'; var cls = require('../lib/class') @@ -1435,9 +1391,6 @@ module.exports = function (element) { i.scrollbarXLeft = h.toInt((i.negativeScrollAdjustment + element.scrollLeft) * (i.railXWidth - i.scrollbarXWidth) / (i.contentWidth - i.containerWidth)); } else { i.scrollbarXActive = false; - i.scrollbarXWidth = 0; - i.scrollbarXLeft = 0; - element.scrollLeft = 0; } if (!i.settings.suppressScrollY && i.containerHeight + i.settings.scrollYMarginOffset < i.contentHeight) { @@ -1448,9 +1401,6 @@ module.exports = function (element) { i.scrollbarYTop = h.toInt(element.scrollTop * (i.railYHeight - i.scrollbarYHeight) / (i.contentHeight - i.containerHeight)); } else { i.scrollbarYActive = false; - i.scrollbarYHeight = 0; - i.scrollbarYTop = 0; - updateScroll(element, 'top', 0); } if (i.scrollbarXLeft >= i.railXWidth - i.scrollbarXWidth) { @@ -1462,14 +1412,25 @@ module.exports = function (element) { updateCss(element, i); - cls[i.scrollbarXActive ? 'add' : 'remove'](element, 'ps-active-x'); - cls[i.scrollbarYActive ? 'add' : 'remove'](element, 'ps-active-y'); + if (i.scrollbarXActive) { + cls.add(element, 'ps-active-x'); + } else { + cls.remove(element, 'ps-active-x'); + i.scrollbarXWidth = 0; + i.scrollbarXLeft = 0; + updateScroll(element, 'left', 0); + } + if (i.scrollbarYActive) { + cls.add(element, 'ps-active-y'); + } else { + cls.remove(element, 'ps-active-y'); + i.scrollbarYHeight = 0; + i.scrollbarYTop = 0; + updateScroll(element, 'top', 0); + } }; },{"../lib/class":2,"../lib/dom":3,"../lib/helper":6,"./instances":18,"./update-scroll":20}],20:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ 'use strict'; var instances = require('./instances'); @@ -1512,29 +1473,25 @@ module.exports = function (element, axis, value) { } if (axis === 'top' && value <= 0) { - element.scrollTop = 0; + element.scrollTop = value = 0; // don't allow negative scroll element.dispatchEvent(yStartEvent); - return; // don't allow negative scroll } if (axis === 'left' && value <= 0) { - element.scrollLeft = 0; + element.scrollLeft = value = 0; // don't allow negative scroll element.dispatchEvent(xStartEvent); - return; // don't allow negative scroll } var i = instances.get(element); - if (axis === 'top' && value > i.contentHeight - i.containerHeight) { - element.scrollTop = i.contentHeight - i.containerHeight; + if (axis === 'top' && value >= i.contentHeight - i.containerHeight) { + element.scrollTop = value = i.contentHeight - i.containerHeight; // don't allow scroll past container element.dispatchEvent(yEndEvent); - return; // don't allow scroll past container } - if (axis === 'left' && value > i.contentWidth - i.containerWidth) { - element.scrollLeft = i.contentWidth - i.containerWidth; + if (axis === 'left' && value >= i.contentWidth - i.containerWidth) { + element.scrollLeft = value = i.contentWidth - i.containerWidth; // don't allow scroll past container element.dispatchEvent(xEndEvent); - return; // don't allow scroll past container } if (!lastTop) { @@ -1574,15 +1531,13 @@ module.exports = function (element, axis, value) { }; },{"./instances":18}],21:[function(require,module,exports){ -/* Copyright (c) 2015 Hyunje Alex Jun and other contributors - * Licensed under the MIT License - */ 'use strict'; var d = require('../lib/dom') , h = require('../lib/helper') , instances = require('./instances') - , updateGeometry = require('./update-geometry'); + , updateGeometry = require('./update-geometry') + , updateScroll = require('./update-scroll'); module.exports = function (element) { var i = instances.get(element); @@ -1606,8 +1561,12 @@ module.exports = function (element) { updateGeometry(element); + // Update top/left scroll to trigger events + updateScroll(element, 'top', element.scrollTop); + updateScroll(element, 'left', element.scrollLeft); + d.css(i.scrollbarXRail, 'display', ''); d.css(i.scrollbarYRail, 'display', ''); }; -},{"../lib/dom":3,"../lib/helper":6,"./instances":18,"./update-geometry":19}]},{},[1]); +},{"../lib/dom":3,"../lib/helper":6,"./instances":18,"./update-geometry":19,"./update-scroll":20}]},{},[1]); diff --git a/web/static/js/perfect-scrollbar-0.6.10.jquery.min.js b/web/static/js/perfect-scrollbar-0.6.10.jquery.min.js new file mode 100644 index 000000000..af39018e1 --- /dev/null +++ b/web/static/js/perfect-scrollbar-0.6.10.jquery.min.js @@ -0,0 +1,2 @@ +/* perfect-scrollbar v0.6.10 */ +!function t(e,n,r){function o(l,s){if(!n[l]){if(!e[l]){var a="function"==typeof require&&require;if(!s&&a)return a(l,!0);if(i)return i(l,!0);var c=new Error("Cannot find module '"+l+"'");throw c.code="MODULE_NOT_FOUND",c}var u=n[l]={exports:{}};e[l][0].call(u.exports,function(t){var n=e[l][1][t];return o(n?n:t)},u,u.exports,t,e,n,r)}return n[l].exports}for(var i="function"==typeof require&&require,l=0;l<r.length;l++)o(r[l]);return o}({1:[function(t,e,n){"use strict";function r(t){t.fn.perfectScrollbar=function(e){return this.each(function(){if("object"==typeof e||"undefined"==typeof e){var n=e;i.get(this)||o.initialize(this,n)}else{var r=e;"update"===r?o.update(this):"destroy"===r&&o.destroy(this)}return t(this)})}}var o=t("../main"),i=t("../plugin/instances");if("function"==typeof define&&define.amd)define(["jquery"],r);else{var l=window.jQuery?window.jQuery:window.$;"undefined"!=typeof l&&r(l)}e.exports=r},{"../main":7,"../plugin/instances":18}],2:[function(t,e,n){"use strict";function r(t,e){var n=t.className.split(" ");n.indexOf(e)<0&&n.push(e),t.className=n.join(" ")}function o(t,e){var n=t.className.split(" "),r=n.indexOf(e);r>=0&&n.splice(r,1),t.className=n.join(" ")}n.add=function(t,e){t.classList?t.classList.add(e):r(t,e)},n.remove=function(t,e){t.classList?t.classList.remove(e):o(t,e)},n.list=function(t){return t.classList?Array.prototype.slice.apply(t.classList):t.className.split(" ")}},{}],3:[function(t,e,n){"use strict";function r(t,e){return window.getComputedStyle(t)[e]}function o(t,e,n){return"number"==typeof n&&(n=n.toString()+"px"),t.style[e]=n,t}function i(t,e){for(var n in e){var r=e[n];"number"==typeof r&&(r=r.toString()+"px"),t.style[n]=r}return t}var l={};l.e=function(t,e){var n=document.createElement(t);return n.className=e,n},l.appendTo=function(t,e){return e.appendChild(t),t},l.css=function(t,e,n){return"object"==typeof e?i(t,e):"undefined"==typeof n?r(t,e):o(t,e,n)},l.matches=function(t,e){return"undefined"!=typeof t.matches?t.matches(e):"undefined"!=typeof t.matchesSelector?t.matchesSelector(e):"undefined"!=typeof t.webkitMatchesSelector?t.webkitMatchesSelector(e):"undefined"!=typeof t.mozMatchesSelector?t.mozMatchesSelector(e):"undefined"!=typeof t.msMatchesSelector?t.msMatchesSelector(e):void 0},l.remove=function(t){"undefined"!=typeof t.remove?t.remove():t.parentNode&&t.parentNode.removeChild(t)},l.queryChildren=function(t,e){return Array.prototype.filter.call(t.childNodes,function(t){return l.matches(t,e)})},e.exports=l},{}],4:[function(t,e,n){"use strict";var r=function(t){this.element=t,this.events={}};r.prototype.bind=function(t,e){"undefined"==typeof this.events[t]&&(this.events[t]=[]),this.events[t].push(e),this.element.addEventListener(t,e,!1)},r.prototype.unbind=function(t,e){var n="undefined"!=typeof e;this.events[t]=this.events[t].filter(function(r){return n&&r!==e?!0:(this.element.removeEventListener(t,r,!1),!1)},this)},r.prototype.unbindAll=function(){for(var t in this.events)this.unbind(t)};var o=function(){this.eventElements=[]};o.prototype.eventElement=function(t){var e=this.eventElements.filter(function(e){return e.element===t})[0];return"undefined"==typeof e&&(e=new r(t),this.eventElements.push(e)),e},o.prototype.bind=function(t,e,n){this.eventElement(t).bind(e,n)},o.prototype.unbind=function(t,e,n){this.eventElement(t).unbind(e,n)},o.prototype.unbindAll=function(){for(var t=0;t<this.eventElements.length;t++)this.eventElements[t].unbindAll()},o.prototype.once=function(t,e,n){var r=this.eventElement(t),o=function(t){r.unbind(e,o),n(t)};r.bind(e,o)},e.exports=o},{}],5:[function(t,e,n){"use strict";e.exports=function(){function t(){return Math.floor(65536*(1+Math.random())).toString(16).substring(1)}return function(){return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()}}()},{}],6:[function(t,e,n){"use strict";var r=t("./class"),o=t("./dom");n.toInt=function(t){return parseInt(t,10)||0},n.clone=function(t){if(null===t)return null;if("object"==typeof t){var e={};for(var n in t)e[n]=this.clone(t[n]);return e}return t},n.extend=function(t,e){var n=this.clone(t);for(var r in e)n[r]=this.clone(e[r]);return n},n.isEditable=function(t){return o.matches(t,"input,[contenteditable]")||o.matches(t,"select,[contenteditable]")||o.matches(t,"textarea,[contenteditable]")||o.matches(t,"button,[contenteditable]")},n.removePsClasses=function(t){for(var e=r.list(t),n=0;n<e.length;n++){var o=e[n];0===o.indexOf("ps-")&&r.remove(t,o)}},n.outerWidth=function(t){return this.toInt(o.css(t,"width"))+this.toInt(o.css(t,"paddingLeft"))+this.toInt(o.css(t,"paddingRight"))+this.toInt(o.css(t,"borderLeftWidth"))+this.toInt(o.css(t,"borderRightWidth"))},n.startScrolling=function(t,e){r.add(t,"ps-in-scrolling"),"undefined"!=typeof e?r.add(t,"ps-"+e):(r.add(t,"ps-x"),r.add(t,"ps-y"))},n.stopScrolling=function(t,e){r.remove(t,"ps-in-scrolling"),"undefined"!=typeof e?r.remove(t,"ps-"+e):(r.remove(t,"ps-x"),r.remove(t,"ps-y"))},n.env={isWebKit:"WebkitAppearance"in document.documentElement.style,supportsTouch:"ontouchstart"in window||window.DocumentTouch&&document instanceof window.DocumentTouch,supportsIePointer:null!==window.navigator.msMaxTouchPoints}},{"./class":2,"./dom":3}],7:[function(t,e,n){"use strict";var r=t("./plugin/destroy"),o=t("./plugin/initialize"),i=t("./plugin/update");e.exports={initialize:o,update:i,destroy:r}},{"./plugin/destroy":9,"./plugin/initialize":17,"./plugin/update":21}],8:[function(t,e,n){"use strict";e.exports={maxScrollbarLength:null,minScrollbarLength:null,scrollXMarginOffset:0,scrollYMarginOffset:0,stopPropagationOnClick:!0,suppressScrollX:!1,suppressScrollY:!1,swipePropagation:!0,useBothWheelAxes:!1,useKeyboard:!0,useSelectionScroll:!1,wheelPropagation:!1,wheelSpeed:1,theme:"default"}},{}],9:[function(t,e,n){"use strict";var r=t("../lib/dom"),o=t("../lib/helper"),i=t("./instances");e.exports=function(t){var e=i.get(t);e&&(e.event.unbindAll(),r.remove(e.scrollbarX),r.remove(e.scrollbarY),r.remove(e.scrollbarXRail),r.remove(e.scrollbarYRail),o.removePsClasses(t),i.remove(t))}},{"../lib/dom":3,"../lib/helper":6,"./instances":18}],10:[function(t,e,n){"use strict";function r(t,e){function n(t){return t.getBoundingClientRect()}e.settings.stopPropagationOnClick&&e.event.bind(e.scrollbarY,"click",function(t){t.stopPropagation()}),e.event.bind(e.scrollbarYRail,"click",function(r){var i=o.toInt(e.scrollbarYHeight/2),a=e.railYRatio*(r.pageY-window.pageYOffset-n(e.scrollbarYRail).top-i),c=e.railYRatio*(e.railYHeight-e.scrollbarYHeight),u=a/c;0>u?u=0:u>1&&(u=1),s(t,"top",(e.contentHeight-e.containerHeight)*u),l(t),r.stopPropagation()}),e.settings.stopPropagationOnClick&&e.event.bind(e.scrollbarY,"click",function(t){t.stopPropagation()}),e.event.bind(e.scrollbarXRail,"click",function(r){var i=o.toInt(e.scrollbarXWidth/2),a=e.railXRatio*(r.pageX-window.pageXOffset-n(e.scrollbarXRail).left-i),c=e.railXRatio*(e.railXWidth-e.scrollbarXWidth),u=a/c;0>u?u=0:u>1&&(u=1),s(t,"left",(e.contentWidth-e.containerWidth)*u-e.negativeScrollAdjustment),l(t),r.stopPropagation()})}var o=t("../../lib/helper"),i=t("../instances"),l=t("../update-geometry"),s=t("../update-scroll");e.exports=function(t){var e=i.get(t);r(t,e)}},{"../../lib/helper":6,"../instances":18,"../update-geometry":19,"../update-scroll":20}],11:[function(t,e,n){"use strict";function r(t,e){function n(n){var o=r+n*e.railXRatio,i=Math.max(0,e.scrollbarXRail.getBoundingClientRect().left)+e.railXRatio*(e.railXWidth-e.scrollbarXWidth);0>o?e.scrollbarXLeft=0:o>i?e.scrollbarXLeft=i:e.scrollbarXLeft=o;var s=l.toInt(e.scrollbarXLeft*(e.contentWidth-e.containerWidth)/(e.containerWidth-e.railXRatio*e.scrollbarXWidth))-e.negativeScrollAdjustment;c(t,"left",s)}var r=null,o=null,s=function(e){n(e.pageX-o),a(t),e.stopPropagation(),e.preventDefault()},u=function(){l.stopScrolling(t,"x"),e.event.unbind(e.ownerDocument,"mousemove",s)};e.event.bind(e.scrollbarX,"mousedown",function(n){o=n.pageX,r=l.toInt(i.css(e.scrollbarX,"left"))*e.railXRatio,l.startScrolling(t,"x"),e.event.bind(e.ownerDocument,"mousemove",s),e.event.once(e.ownerDocument,"mouseup",u),n.stopPropagation(),n.preventDefault()})}function o(t,e){function n(n){var o=r+n*e.railYRatio,i=Math.max(0,e.scrollbarYRail.getBoundingClientRect().top)+e.railYRatio*(e.railYHeight-e.scrollbarYHeight);0>o?e.scrollbarYTop=0:o>i?e.scrollbarYTop=i:e.scrollbarYTop=o;var s=l.toInt(e.scrollbarYTop*(e.contentHeight-e.containerHeight)/(e.containerHeight-e.railYRatio*e.scrollbarYHeight));c(t,"top",s)}var r=null,o=null,s=function(e){n(e.pageY-o),a(t),e.stopPropagation(),e.preventDefault()},u=function(){l.stopScrolling(t,"y"),e.event.unbind(e.ownerDocument,"mousemove",s)};e.event.bind(e.scrollbarY,"mousedown",function(n){o=n.pageY,r=l.toInt(i.css(e.scrollbarY,"top"))*e.railYRatio,l.startScrolling(t,"y"),e.event.bind(e.ownerDocument,"mousemove",s),e.event.once(e.ownerDocument,"mouseup",u),n.stopPropagation(),n.preventDefault()})}var i=t("../../lib/dom"),l=t("../../lib/helper"),s=t("../instances"),a=t("../update-geometry"),c=t("../update-scroll");e.exports=function(t){var e=s.get(t);r(t,e),o(t,e)}},{"../../lib/dom":3,"../../lib/helper":6,"../instances":18,"../update-geometry":19,"../update-scroll":20}],12:[function(t,e,n){"use strict";function r(t,e){function n(n,r){var o=t.scrollTop;if(0===n){if(!e.scrollbarYActive)return!1;if(0===o&&r>0||o>=e.contentHeight-e.containerHeight&&0>r)return!e.settings.wheelPropagation}var i=t.scrollLeft;if(0===r){if(!e.scrollbarXActive)return!1;if(0===i&&0>n||i>=e.contentWidth-e.containerWidth&&n>0)return!e.settings.wheelPropagation}return!0}var r=!1;e.event.bind(t,"mouseenter",function(){r=!0}),e.event.bind(t,"mouseleave",function(){r=!1});var l=!1;e.event.bind(e.ownerDocument,"keydown",function(c){if(!c.isDefaultPrevented||!c.isDefaultPrevented()){var u=i.matches(e.scrollbarX,":focus")||i.matches(e.scrollbarY,":focus");if(r||u){var d=document.activeElement?document.activeElement:e.ownerDocument.activeElement;if(d){for(;d.shadowRoot;)d=d.shadowRoot.activeElement;if(o.isEditable(d))return}var p=0,f=0;switch(c.which){case 37:p=-30;break;case 38:f=30;break;case 39:p=30;break;case 40:f=-30;break;case 33:f=90;break;case 32:f=c.shiftKey?90:-90;break;case 34:f=-90;break;case 35:f=c.ctrlKey?-e.contentHeight:-e.containerHeight;break;case 36:f=c.ctrlKey?t.scrollTop:e.containerHeight;break;default:return}a(t,"top",t.scrollTop-f),a(t,"left",t.scrollLeft+p),s(t),l=n(p,f),l&&c.preventDefault()}}})}var o=t("../../lib/helper"),i=t("../../lib/dom"),l=t("../instances"),s=t("../update-geometry"),a=t("../update-scroll");e.exports=function(t){var e=l.get(t);r(t,e)}},{"../../lib/dom":3,"../../lib/helper":6,"../instances":18,"../update-geometry":19,"../update-scroll":20}],13:[function(t,e,n){"use strict";function r(t,e){function n(n,r){var o=t.scrollTop;if(0===n){if(!e.scrollbarYActive)return!1;if(0===o&&r>0||o>=e.contentHeight-e.containerHeight&&0>r)return!e.settings.wheelPropagation}var i=t.scrollLeft;if(0===r){if(!e.scrollbarXActive)return!1;if(0===i&&0>n||i>=e.contentWidth-e.containerWidth&&n>0)return!e.settings.wheelPropagation}return!0}function r(t){var e=t.deltaX,n=-1*t.deltaY;return("undefined"==typeof e||"undefined"==typeof n)&&(e=-1*t.wheelDeltaX/6,n=t.wheelDeltaY/6),t.deltaMode&&1===t.deltaMode&&(e*=10,n*=10),e!==e&&n!==n&&(e=0,n=t.wheelDelta),[e,n]}function o(e,n){var r=t.querySelector("textarea:hover");if(r){var o=r.scrollHeight-r.clientHeight;if(o>0&&!(0===r.scrollTop&&n>0||r.scrollTop===o&&0>n))return!0;var i=r.scrollLeft-r.clientWidth;if(i>0&&!(0===r.scrollLeft&&0>e||r.scrollLeft===i&&e>0))return!0}return!1}function s(s){var c=r(s),u=c[0],d=c[1];o(u,d)||(a=!1,e.settings.useBothWheelAxes?e.scrollbarYActive&&!e.scrollbarXActive?(d?l(t,"top",t.scrollTop-d*e.settings.wheelSpeed):l(t,"top",t.scrollTop+u*e.settings.wheelSpeed),a=!0):e.scrollbarXActive&&!e.scrollbarYActive&&(u?l(t,"left",t.scrollLeft+u*e.settings.wheelSpeed):l(t,"left",t.scrollLeft-d*e.settings.wheelSpeed),a=!0):(l(t,"top",t.scrollTop-d*e.settings.wheelSpeed),l(t,"left",t.scrollLeft+u*e.settings.wheelSpeed)),i(t),a=a||n(u,d),a&&(s.stopPropagation(),s.preventDefault()))}var a=!1;"undefined"!=typeof window.onwheel?e.event.bind(t,"wheel",s):"undefined"!=typeof window.onmousewheel&&e.event.bind(t,"mousewheel",s)}var o=t("../instances"),i=t("../update-geometry"),l=t("../update-scroll");e.exports=function(t){var e=o.get(t);r(t,e)}},{"../instances":18,"../update-geometry":19,"../update-scroll":20}],14:[function(t,e,n){"use strict";function r(t,e){e.event.bind(t,"scroll",function(){i(t)})}var o=t("../instances"),i=t("../update-geometry");e.exports=function(t){var e=o.get(t);r(t,e)}},{"../instances":18,"../update-geometry":19}],15:[function(t,e,n){"use strict";function r(t,e){function n(){var t=window.getSelection?window.getSelection():document.getSelection?document.getSelection():"";return 0===t.toString().length?null:t.getRangeAt(0).commonAncestorContainer}function r(){c||(c=setInterval(function(){return i.get(t)?(s(t,"top",t.scrollTop+u.top),s(t,"left",t.scrollLeft+u.left),void l(t)):void clearInterval(c)},50))}function a(){c&&(clearInterval(c),c=null),o.stopScrolling(t)}var c=null,u={top:0,left:0},d=!1;e.event.bind(e.ownerDocument,"selectionchange",function(){t.contains(n())?d=!0:(d=!1,a())}),e.event.bind(window,"mouseup",function(){d&&(d=!1,a())}),e.event.bind(window,"mousemove",function(e){if(d){var n={x:e.pageX,y:e.pageY},i={left:t.offsetLeft,right:t.offsetLeft+t.offsetWidth,top:t.offsetTop,bottom:t.offsetTop+t.offsetHeight};n.x<i.left+3?(u.left=-5,o.startScrolling(t,"x")):n.x>i.right-3?(u.left=5,o.startScrolling(t,"x")):u.left=0,n.y<i.top+3?(i.top+3-n.y<5?u.top=-5:u.top=-20,o.startScrolling(t,"y")):n.y>i.bottom-3?(n.y-i.bottom+3<5?u.top=5:u.top=20,o.startScrolling(t,"y")):u.top=0,0===u.top&&0===u.left?a():r()}})}var o=t("../../lib/helper"),i=t("../instances"),l=t("../update-geometry"),s=t("../update-scroll");e.exports=function(t){var e=i.get(t);r(t,e)}},{"../../lib/helper":6,"../instances":18,"../update-geometry":19,"../update-scroll":20}],16:[function(t,e,n){"use strict";function r(t,e,n,r){function s(n,r){var o=t.scrollTop,i=t.scrollLeft,l=Math.abs(n),s=Math.abs(r);if(s>l){if(0>r&&o===e.contentHeight-e.containerHeight||r>0&&0===o)return!e.settings.swipePropagation}else if(l>s&&(0>n&&i===e.contentWidth-e.containerWidth||n>0&&0===i))return!e.settings.swipePropagation;return!0}function a(e,n){l(t,"top",t.scrollTop-n),l(t,"left",t.scrollLeft-e),i(t)}function c(){Y=!0}function u(){Y=!1}function d(t){return t.targetTouches?t.targetTouches[0]:t}function p(t){return t.targetTouches&&1===t.targetTouches.length?!0:t.pointerType&&"mouse"!==t.pointerType&&t.pointerType!==t.MSPOINTER_TYPE_MOUSE?!0:!1}function f(t){if(p(t)){w=!0;var e=d(t);v.pageX=e.pageX,v.pageY=e.pageY,g=(new Date).getTime(),null!==y&&clearInterval(y),t.stopPropagation()}}function h(t){if(!Y&&w&&p(t)){var e=d(t),n={pageX:e.pageX,pageY:e.pageY},r=n.pageX-v.pageX,o=n.pageY-v.pageY;a(r,o),v=n;var i=(new Date).getTime(),l=i-g;l>0&&(m.x=r/l,m.y=o/l,g=i),s(r,o)&&(t.stopPropagation(),t.preventDefault())}}function b(){!Y&&w&&(w=!1,clearInterval(y),y=setInterval(function(){return o.get(t)?Math.abs(m.x)<.01&&Math.abs(m.y)<.01?void clearInterval(y):(a(30*m.x,30*m.y),m.x*=.8,void(m.y*=.8)):void clearInterval(y)},10))}var v={},g=0,m={},y=null,Y=!1,w=!1;n&&(e.event.bind(window,"touchstart",c),e.event.bind(window,"touchend",u),e.event.bind(t,"touchstart",f),e.event.bind(t,"touchmove",h),e.event.bind(t,"touchend",b)),r&&(window.PointerEvent?(e.event.bind(window,"pointerdown",c),e.event.bind(window,"pointerup",u),e.event.bind(t,"pointerdown",f),e.event.bind(t,"pointermove",h),e.event.bind(t,"pointerup",b)):window.MSPointerEvent&&(e.event.bind(window,"MSPointerDown",c),e.event.bind(window,"MSPointerUp",u),e.event.bind(t,"MSPointerDown",f),e.event.bind(t,"MSPointerMove",h),e.event.bind(t,"MSPointerUp",b)))}var o=t("../instances"),i=t("../update-geometry"),l=t("../update-scroll");e.exports=function(t,e,n){var i=o.get(t);r(t,i,e,n)}},{"../instances":18,"../update-geometry":19,"../update-scroll":20}],17:[function(t,e,n){"use strict";var r=t("../lib/class"),o=t("../lib/helper"),i=t("./instances"),l=t("./update-geometry"),s=t("./handler/click-rail"),a=t("./handler/drag-scrollbar"),c=t("./handler/keyboard"),u=t("./handler/mouse-wheel"),d=t("./handler/native-scroll"),p=t("./handler/selection"),f=t("./handler/touch");e.exports=function(t,e){e="object"==typeof e?e:{},r.add(t,"ps-container");var n=i.add(t);n.settings=o.extend(n.settings,e),r.add(t,"ps-theme-"+n.settings.theme),s(t),a(t),u(t),d(t),n.settings.useSelectionScroll&&p(t),(o.env.supportsTouch||o.env.supportsIePointer)&&f(t,o.env.supportsTouch,o.env.supportsIePointer),n.settings.useKeyboard&&c(t),l(t)}},{"../lib/class":2,"../lib/helper":6,"./handler/click-rail":10,"./handler/drag-scrollbar":11,"./handler/keyboard":12,"./handler/mouse-wheel":13,"./handler/native-scroll":14,"./handler/selection":15,"./handler/touch":16,"./instances":18,"./update-geometry":19}],18:[function(t,e,n){"use strict";function r(t){function e(){s.add(t,"ps-focus")}function n(){s.remove(t,"ps-focus")}var r=this;r.settings=p.clone(c),r.containerWidth=null,r.containerHeight=null,r.contentWidth=null,r.contentHeight=null,r.isRtl="rtl"===a.css(t,"direction"),r.isNegativeScroll=function(){var e=t.scrollLeft,n=null;return t.scrollLeft=-1,n=t.scrollLeft<0,t.scrollLeft=e,n}(),r.negativeScrollAdjustment=r.isNegativeScroll?t.scrollWidth-t.clientWidth:0,r.event=new u,r.ownerDocument=t.ownerDocument||document,r.scrollbarXRail=a.appendTo(a.e("div","ps-scrollbar-x-rail"),t),r.scrollbarX=a.appendTo(a.e("div","ps-scrollbar-x"),r.scrollbarXRail),r.scrollbarX.setAttribute("tabindex",0),r.event.bind(r.scrollbarX,"focus",e),r.event.bind(r.scrollbarX,"blur",n),r.scrollbarXActive=null,r.scrollbarXWidth=null,r.scrollbarXLeft=null,r.scrollbarXBottom=p.toInt(a.css(r.scrollbarXRail,"bottom")),r.isScrollbarXUsingBottom=r.scrollbarXBottom===r.scrollbarXBottom,r.scrollbarXTop=r.isScrollbarXUsingBottom?null:p.toInt(a.css(r.scrollbarXRail,"top")),r.railBorderXWidth=p.toInt(a.css(r.scrollbarXRail,"borderLeftWidth"))+p.toInt(a.css(r.scrollbarXRail,"borderRightWidth")),a.css(r.scrollbarXRail,"display","block"),r.railXMarginWidth=p.toInt(a.css(r.scrollbarXRail,"marginLeft"))+p.toInt(a.css(r.scrollbarXRail,"marginRight")),a.css(r.scrollbarXRail,"display",""),r.railXWidth=null,r.railXRatio=null,r.scrollbarYRail=a.appendTo(a.e("div","ps-scrollbar-y-rail"),t),r.scrollbarY=a.appendTo(a.e("div","ps-scrollbar-y"),r.scrollbarYRail),r.scrollbarY.setAttribute("tabindex",0),r.event.bind(r.scrollbarY,"focus",e),r.event.bind(r.scrollbarY,"blur",n),r.scrollbarYActive=null,r.scrollbarYHeight=null,r.scrollbarYTop=null,r.scrollbarYRight=p.toInt(a.css(r.scrollbarYRail,"right")),r.isScrollbarYUsingRight=r.scrollbarYRight===r.scrollbarYRight,r.scrollbarYLeft=r.isScrollbarYUsingRight?null:p.toInt(a.css(r.scrollbarYRail,"left")),r.scrollbarYOuterWidth=r.isRtl?p.outerWidth(r.scrollbarY):null,r.railBorderYWidth=p.toInt(a.css(r.scrollbarYRail,"borderTopWidth"))+p.toInt(a.css(r.scrollbarYRail,"borderBottomWidth")),a.css(r.scrollbarYRail,"display","block"),r.railYMarginHeight=p.toInt(a.css(r.scrollbarYRail,"marginTop"))+p.toInt(a.css(r.scrollbarYRail,"marginBottom")),a.css(r.scrollbarYRail,"display",""),r.railYHeight=null,r.railYRatio=null}function o(t){return"undefined"==typeof t.dataset?t.getAttribute("data-ps-id"):t.dataset.psId}function i(t,e){"undefined"==typeof t.dataset?t.setAttribute("data-ps-id",e):t.dataset.psId=e}function l(t){"undefined"==typeof t.dataset?t.removeAttribute("data-ps-id"):delete t.dataset.psId}var s=t("../lib/class"),a=t("../lib/dom"),c=t("./default-setting"),u=t("../lib/event-manager"),d=t("../lib/guid"),p=t("../lib/helper"),f={};n.add=function(t){var e=d();return i(t,e),f[e]=new r(t),f[e]},n.remove=function(t){delete f[o(t)],l(t)},n.get=function(t){return f[o(t)]}},{"../lib/class":2,"../lib/dom":3,"../lib/event-manager":4,"../lib/guid":5,"../lib/helper":6,"./default-setting":8}],19:[function(t,e,n){"use strict";function r(t,e){return t.settings.minScrollbarLength&&(e=Math.max(e,t.settings.minScrollbarLength)),t.settings.maxScrollbarLength&&(e=Math.min(e,t.settings.maxScrollbarLength)),e}function o(t,e){var n={width:e.railXWidth};e.isRtl?n.left=e.negativeScrollAdjustment+t.scrollLeft+e.containerWidth-e.contentWidth:n.left=t.scrollLeft,e.isScrollbarXUsingBottom?n.bottom=e.scrollbarXBottom-t.scrollTop:n.top=e.scrollbarXTop+t.scrollTop,l.css(e.scrollbarXRail,n);var r={top:t.scrollTop,height:e.railYHeight};e.isScrollbarYUsingRight?e.isRtl?r.right=e.contentWidth-(e.negativeScrollAdjustment+t.scrollLeft)-e.scrollbarYRight-e.scrollbarYOuterWidth:r.right=e.scrollbarYRight-t.scrollLeft:e.isRtl?r.left=e.negativeScrollAdjustment+t.scrollLeft+2*e.containerWidth-e.contentWidth-e.scrollbarYLeft-e.scrollbarYOuterWidth:r.left=e.scrollbarYLeft+t.scrollLeft,l.css(e.scrollbarYRail,r),l.css(e.scrollbarX,{left:e.scrollbarXLeft,width:e.scrollbarXWidth-e.railBorderXWidth}),l.css(e.scrollbarY,{top:e.scrollbarYTop,height:e.scrollbarYHeight-e.railBorderYWidth})}var i=t("../lib/class"),l=t("../lib/dom"),s=t("../lib/helper"),a=t("./instances"),c=t("./update-scroll");e.exports=function(t){var e=a.get(t);e.containerWidth=t.clientWidth,e.containerHeight=t.clientHeight,e.contentWidth=t.scrollWidth,e.contentHeight=t.scrollHeight;var n;t.contains(e.scrollbarXRail)||(n=l.queryChildren(t,".ps-scrollbar-x-rail"),n.length>0&&n.forEach(function(t){l.remove(t)}),l.appendTo(e.scrollbarXRail,t)),t.contains(e.scrollbarYRail)||(n=l.queryChildren(t,".ps-scrollbar-y-rail"),n.length>0&&n.forEach(function(t){l.remove(t)}),l.appendTo(e.scrollbarYRail,t)),!e.settings.suppressScrollX&&e.containerWidth+e.settings.scrollXMarginOffset<e.contentWidth?(e.scrollbarXActive=!0,e.railXWidth=e.containerWidth-e.railXMarginWidth,e.railXRatio=e.containerWidth/e.railXWidth,e.scrollbarXWidth=r(e,s.toInt(e.railXWidth*e.containerWidth/e.contentWidth)),e.scrollbarXLeft=s.toInt((e.negativeScrollAdjustment+t.scrollLeft)*(e.railXWidth-e.scrollbarXWidth)/(e.contentWidth-e.containerWidth))):e.scrollbarXActive=!1,!e.settings.suppressScrollY&&e.containerHeight+e.settings.scrollYMarginOffset<e.contentHeight?(e.scrollbarYActive=!0,e.railYHeight=e.containerHeight-e.railYMarginHeight,e.railYRatio=e.containerHeight/e.railYHeight,e.scrollbarYHeight=r(e,s.toInt(e.railYHeight*e.containerHeight/e.contentHeight)),e.scrollbarYTop=s.toInt(t.scrollTop*(e.railYHeight-e.scrollbarYHeight)/(e.contentHeight-e.containerHeight))):e.scrollbarYActive=!1,e.scrollbarXLeft>=e.railXWidth-e.scrollbarXWidth&&(e.scrollbarXLeft=e.railXWidth-e.scrollbarXWidth),e.scrollbarYTop>=e.railYHeight-e.scrollbarYHeight&&(e.scrollbarYTop=e.railYHeight-e.scrollbarYHeight),o(t,e),e.scrollbarXActive?i.add(t,"ps-active-x"):(i.remove(t,"ps-active-x"),e.scrollbarXWidth=0,e.scrollbarXLeft=0,c(t,"left",0)),e.scrollbarYActive?i.add(t,"ps-active-y"):(i.remove(t,"ps-active-y"),e.scrollbarYHeight=0,e.scrollbarYTop=0,c(t,"top",0))}},{"../lib/class":2,"../lib/dom":3,"../lib/helper":6,"./instances":18,"./update-scroll":20}],20:[function(t,e,n){"use strict";var r,o,i=t("./instances"),l=document.createEvent("Event"),s=document.createEvent("Event"),a=document.createEvent("Event"),c=document.createEvent("Event"),u=document.createEvent("Event"),d=document.createEvent("Event"),p=document.createEvent("Event"),f=document.createEvent("Event"),h=document.createEvent("Event"),b=document.createEvent("Event");l.initEvent("ps-scroll-up",!0,!0),s.initEvent("ps-scroll-down",!0,!0),a.initEvent("ps-scroll-left",!0,!0),c.initEvent("ps-scroll-right",!0,!0),u.initEvent("ps-scroll-y",!0,!0),d.initEvent("ps-scroll-x",!0,!0),p.initEvent("ps-x-reach-start",!0,!0),f.initEvent("ps-x-reach-end",!0,!0),h.initEvent("ps-y-reach-start",!0,!0),b.initEvent("ps-y-reach-end",!0,!0),e.exports=function(t,e,n){if("undefined"==typeof t)throw"You must provide an element to the update-scroll function";if("undefined"==typeof e)throw"You must provide an axis to the update-scroll function";if("undefined"==typeof n)throw"You must provide a value to the update-scroll function";"top"===e&&0>=n&&(t.scrollTop=n=0,t.dispatchEvent(h)),"left"===e&&0>=n&&(t.scrollLeft=n=0,t.dispatchEvent(p));var v=i.get(t);"top"===e&&n>=v.contentHeight-v.containerHeight&&(t.scrollTop=n=v.contentHeight-v.containerHeight,t.dispatchEvent(b)),"left"===e&&n>=v.contentWidth-v.containerWidth&&(t.scrollLeft=n=v.contentWidth-v.containerWidth,t.dispatchEvent(f)),r||(r=t.scrollTop),o||(o=t.scrollLeft),"top"===e&&r>n&&t.dispatchEvent(l),"top"===e&&n>r&&t.dispatchEvent(s),"left"===e&&o>n&&t.dispatchEvent(a),"left"===e&&n>o&&t.dispatchEvent(c),"top"===e&&(t.scrollTop=r=n,t.dispatchEvent(u)),"left"===e&&(t.scrollLeft=o=n,t.dispatchEvent(d))}},{"./instances":18}],21:[function(t,e,n){"use strict";var r=t("../lib/dom"),o=t("../lib/helper"),i=t("./instances"),l=t("./update-geometry"),s=t("./update-scroll");e.exports=function(t){var e=i.get(t);e&&(e.negativeScrollAdjustment=e.isNegativeScroll?t.scrollWidth-t.clientWidth:0,r.css(e.scrollbarXRail,"display","block"),r.css(e.scrollbarYRail,"display","block"),e.railXMarginWidth=o.toInt(r.css(e.scrollbarXRail,"marginLeft"))+o.toInt(r.css(e.scrollbarXRail,"marginRight")),e.railYMarginHeight=o.toInt(r.css(e.scrollbarYRail,"marginTop"))+o.toInt(r.css(e.scrollbarYRail,"marginBottom")),r.css(e.scrollbarXRail,"display","none"),r.css(e.scrollbarYRail,"display","none"),l(t),s(t,"top",t.scrollTop),s(t,"left",t.scrollLeft),r.css(e.scrollbarXRail,"display",""),r.css(e.scrollbarYRail,"display",""))}},{"../lib/dom":3,"../lib/helper":6,"./instances":18,"./update-geometry":19,"./update-scroll":20}]},{},[1]);
\ No newline at end of file diff --git a/web/static/js/perfect-scrollbar-0.6.7.jquery.min.js b/web/static/js/perfect-scrollbar-0.6.7.jquery.min.js deleted file mode 100644 index 8b0f0056c..000000000 --- a/web/static/js/perfect-scrollbar-0.6.7.jquery.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/* perfect-scrollbar v0.6.7 */ -!function t(e,n,r){function o(l,s){if(!n[l]){if(!e[l]){var a="function"==typeof require&&require;if(!s&&a)return a(l,!0);if(i)return i(l,!0);var c=new Error("Cannot find module '"+l+"'");throw c.code="MODULE_NOT_FOUND",c}var u=n[l]={exports:{}};e[l][0].call(u.exports,function(t){var n=e[l][1][t];return o(n?n:t)},u,u.exports,t,e,n,r)}return n[l].exports}for(var i="function"==typeof require&&require,l=0;l<r.length;l++)o(r[l]);return o}({1:[function(t,e,n){"use strict";function r(t){t.fn.perfectScrollbar=function(e){return this.each(function(){if("object"==typeof e||"undefined"==typeof e){var n=e;i.get(this)||o.initialize(this,n)}else{var r=e;"update"===r?o.update(this):"destroy"===r&&o.destroy(this)}return t(this)})}}var o=t("../main"),i=t("../plugin/instances");if("function"==typeof define&&define.amd)define(["jquery"],r);else{var l=window.jQuery?window.jQuery:window.$;"undefined"!=typeof l&&r(l)}e.exports=r},{"../main":7,"../plugin/instances":18}],2:[function(t,e,n){"use strict";function r(t,e){var n=t.className.split(" ");n.indexOf(e)<0&&n.push(e),t.className=n.join(" ")}function o(t,e){var n=t.className.split(" "),r=n.indexOf(e);r>=0&&n.splice(r,1),t.className=n.join(" ")}n.add=function(t,e){t.classList?t.classList.add(e):r(t,e)},n.remove=function(t,e){t.classList?t.classList.remove(e):o(t,e)},n.list=function(t){return t.classList?Array.prototype.slice.apply(t.classList):t.className.split(" ")}},{}],3:[function(t,e,n){"use strict";function r(t,e){return window.getComputedStyle(t)[e]}function o(t,e,n){return"number"==typeof n&&(n=n.toString()+"px"),t.style[e]=n,t}function i(t,e){for(var n in e){var r=e[n];"number"==typeof r&&(r=r.toString()+"px"),t.style[n]=r}return t}var l={};l.e=function(t,e){var n=document.createElement(t);return n.className=e,n},l.appendTo=function(t,e){return e.appendChild(t),t},l.css=function(t,e,n){return"object"==typeof e?i(t,e):"undefined"==typeof n?r(t,e):o(t,e,n)},l.matches=function(t,e){return"undefined"!=typeof t.matches?t.matches(e):"undefined"!=typeof t.matchesSelector?t.matchesSelector(e):"undefined"!=typeof t.webkitMatchesSelector?t.webkitMatchesSelector(e):"undefined"!=typeof t.mozMatchesSelector?t.mozMatchesSelector(e):"undefined"!=typeof t.msMatchesSelector?t.msMatchesSelector(e):void 0},l.remove=function(t){"undefined"!=typeof t.remove?t.remove():t.parentNode&&t.parentNode.removeChild(t)},l.queryChildren=function(t,e){return Array.prototype.filter.call(t.childNodes,function(t){return l.matches(t,e)})},e.exports=l},{}],4:[function(t,e,n){"use strict";var r=function(t){this.element=t,this.events={}};r.prototype.bind=function(t,e){"undefined"==typeof this.events[t]&&(this.events[t]=[]),this.events[t].push(e),this.element.addEventListener(t,e,!1)},r.prototype.unbind=function(t,e){var n="undefined"!=typeof e;this.events[t]=this.events[t].filter(function(r){return n&&r!==e?!0:(this.element.removeEventListener(t,r,!1),!1)},this)},r.prototype.unbindAll=function(){for(var t in this.events)this.unbind(t)};var o=function(){this.eventElements=[]};o.prototype.eventElement=function(t){var e=this.eventElements.filter(function(e){return e.element===t})[0];return"undefined"==typeof e&&(e=new r(t),this.eventElements.push(e)),e},o.prototype.bind=function(t,e,n){this.eventElement(t).bind(e,n)},o.prototype.unbind=function(t,e,n){this.eventElement(t).unbind(e,n)},o.prototype.unbindAll=function(){for(var t=0;t<this.eventElements.length;t++)this.eventElements[t].unbindAll()},o.prototype.once=function(t,e,n){var r=this.eventElement(t),o=function(t){r.unbind(e,o),n(t)};r.bind(e,o)},e.exports=o},{}],5:[function(t,e,n){"use strict";e.exports=function(){function t(){return Math.floor(65536*(1+Math.random())).toString(16).substring(1)}return function(){return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()}}()},{}],6:[function(t,e,n){"use strict";var r=t("./class"),o=t("./dom");n.toInt=function(t){return parseInt(t,10)||0},n.clone=function(t){if(null===t)return null;if("object"==typeof t){var e={};for(var n in t)e[n]=this.clone(t[n]);return e}return t},n.extend=function(t,e){var n=this.clone(t);for(var r in e)n[r]=this.clone(e[r]);return n},n.isEditable=function(t){return o.matches(t,"input,[contenteditable]")||o.matches(t,"select,[contenteditable]")||o.matches(t,"textarea,[contenteditable]")||o.matches(t,"button,[contenteditable]")},n.removePsClasses=function(t){for(var e=r.list(t),n=0;n<e.length;n++){var o=e[n];0===o.indexOf("ps-")&&r.remove(t,o)}},n.outerWidth=function(t){return this.toInt(o.css(t,"width"))+this.toInt(o.css(t,"paddingLeft"))+this.toInt(o.css(t,"paddingRight"))+this.toInt(o.css(t,"borderLeftWidth"))+this.toInt(o.css(t,"borderRightWidth"))},n.startScrolling=function(t,e){r.add(t,"ps-in-scrolling"),"undefined"!=typeof e?r.add(t,"ps-"+e):(r.add(t,"ps-x"),r.add(t,"ps-y"))},n.stopScrolling=function(t,e){r.remove(t,"ps-in-scrolling"),"undefined"!=typeof e?r.remove(t,"ps-"+e):(r.remove(t,"ps-x"),r.remove(t,"ps-y"))},n.env={isWebKit:"WebkitAppearance"in document.documentElement.style,supportsTouch:"ontouchstart"in window||window.DocumentTouch&&document instanceof window.DocumentTouch,supportsIePointer:null!==window.navigator.msMaxTouchPoints}},{"./class":2,"./dom":3}],7:[function(t,e,n){"use strict";var r=t("./plugin/destroy"),o=t("./plugin/initialize"),i=t("./plugin/update");e.exports={initialize:o,update:i,destroy:r}},{"./plugin/destroy":9,"./plugin/initialize":17,"./plugin/update":21}],8:[function(t,e,n){"use strict";e.exports={maxScrollbarLength:null,minScrollbarLength:null,scrollXMarginOffset:0,scrollYMarginOffset:0,stopPropagationOnClick:!0,suppressScrollX:!1,suppressScrollY:!1,swipePropagation:!0,useBothWheelAxes:!1,useKeyboard:!0,useSelectionScroll:!1,wheelPropagation:!1,wheelSpeed:1}},{}],9:[function(t,e,n){"use strict";var r=t("../lib/dom"),o=t("../lib/helper"),i=t("./instances");e.exports=function(t){var e=i.get(t);e&&(e.event.unbindAll(),r.remove(e.scrollbarX),r.remove(e.scrollbarY),r.remove(e.scrollbarXRail),r.remove(e.scrollbarYRail),o.removePsClasses(t),i.remove(t))}},{"../lib/dom":3,"../lib/helper":6,"./instances":18}],10:[function(t,e,n){"use strict";function r(t,e){function n(t){return t.getBoundingClientRect()}e.settings.stopPropagationOnClick&&e.event.bind(e.scrollbarY,"click",function(t){t.stopPropagation()}),e.event.bind(e.scrollbarYRail,"click",function(r){var i=o.toInt(e.scrollbarYHeight/2),a=e.railYRatio*(r.pageY-window.scrollY-n(e.scrollbarYRail).top-i),c=e.railYRatio*(e.railYHeight-e.scrollbarYHeight),u=a/c;0>u?u=0:u>1&&(u=1),s(t,"top",(e.contentHeight-e.containerHeight)*u),l(t),r.stopPropagation()}),e.settings.stopPropagationOnClick&&e.event.bind(e.scrollbarY,"click",function(t){t.stopPropagation()}),e.event.bind(e.scrollbarXRail,"click",function(r){var i=o.toInt(e.scrollbarXWidth/2),a=e.railXRatio*(r.pageX-window.scrollX-n(e.scrollbarXRail).left-i),c=e.railXRatio*(e.railXWidth-e.scrollbarXWidth),u=a/c;0>u?u=0:u>1&&(u=1),s(t,"left",(e.contentWidth-e.containerWidth)*u-e.negativeScrollAdjustment),l(t),r.stopPropagation()})}var o=t("../../lib/helper"),i=t("../instances"),l=t("../update-geometry"),s=t("../update-scroll");e.exports=function(t){var e=i.get(t);r(t,e)}},{"../../lib/helper":6,"../instances":18,"../update-geometry":19,"../update-scroll":20}],11:[function(t,e,n){"use strict";function r(t,e){function n(n){var o=r+n*e.railXRatio,i=e.scrollbarXRail.getBoundingClientRect().left+e.railXRatio*(e.railXWidth-e.scrollbarXWidth);0>o?e.scrollbarXLeft=0:o>i?e.scrollbarXLeft=i:e.scrollbarXLeft=o;var s=l.toInt(e.scrollbarXLeft*(e.contentWidth-e.containerWidth)/(e.containerWidth-e.railXRatio*e.scrollbarXWidth))-e.negativeScrollAdjustment;c(t,"left",s)}var r=null,o=null,s=function(e){n(e.pageX-o),a(t),e.stopPropagation(),e.preventDefault()},u=function(){l.stopScrolling(t,"x"),e.event.unbind(e.ownerDocument,"mousemove",s)};e.event.bind(e.scrollbarX,"mousedown",function(n){o=n.pageX,r=l.toInt(i.css(e.scrollbarX,"left"))*e.railXRatio,l.startScrolling(t,"x"),e.event.bind(e.ownerDocument,"mousemove",s),e.event.once(e.ownerDocument,"mouseup",u),n.stopPropagation(),n.preventDefault()})}function o(t,e){function n(n){var o=r+n*e.railYRatio,i=e.scrollbarYRail.getBoundingClientRect().top+e.railYRatio*(e.railYHeight-e.scrollbarYHeight);0>o?e.scrollbarYTop=0:o>i?e.scrollbarYTop=i:e.scrollbarYTop=o;var s=l.toInt(e.scrollbarYTop*(e.contentHeight-e.containerHeight)/(e.containerHeight-e.railYRatio*e.scrollbarYHeight));c(t,"top",s)}var r=null,o=null,s=function(e){n(e.pageY-o),a(t),e.stopPropagation(),e.preventDefault()},u=function(){l.stopScrolling(t,"y"),e.event.unbind(e.ownerDocument,"mousemove",s)};e.event.bind(e.scrollbarY,"mousedown",function(n){o=n.pageY,r=l.toInt(i.css(e.scrollbarY,"top"))*e.railYRatio,l.startScrolling(t,"y"),e.event.bind(e.ownerDocument,"mousemove",s),e.event.once(e.ownerDocument,"mouseup",u),n.stopPropagation(),n.preventDefault()})}var i=t("../../lib/dom"),l=t("../../lib/helper"),s=t("../instances"),a=t("../update-geometry"),c=t("../update-scroll");e.exports=function(t){var e=s.get(t);r(t,e),o(t,e)}},{"../../lib/dom":3,"../../lib/helper":6,"../instances":18,"../update-geometry":19,"../update-scroll":20}],12:[function(t,e,n){"use strict";function r(t,e){function n(n,r){var o=t.scrollTop;if(0===n){if(!e.scrollbarYActive)return!1;if(0===o&&r>0||o>=e.contentHeight-e.containerHeight&&0>r)return!e.settings.wheelPropagation}var i=t.scrollLeft;if(0===r){if(!e.scrollbarXActive)return!1;if(0===i&&0>n||i>=e.contentWidth-e.containerWidth&&n>0)return!e.settings.wheelPropagation}return!0}var r=!1;e.event.bind(t,"mouseenter",function(){r=!0}),e.event.bind(t,"mouseleave",function(){r=!1});var i=!1;e.event.bind(e.ownerDocument,"keydown",function(a){if((!a.isDefaultPrevented||!a.isDefaultPrevented())&&r){var c=document.activeElement?document.activeElement:e.ownerDocument.activeElement;if(c){for(;c.shadowRoot;)c=c.shadowRoot.activeElement;if(o.isEditable(c))return}var u=0,d=0;switch(a.which){case 37:u=-30;break;case 38:d=30;break;case 39:u=30;break;case 40:d=-30;break;case 33:d=90;break;case 32:d=a.shiftKey?90:-90;break;case 34:d=-90;break;case 35:d=a.ctrlKey?-e.contentHeight:-e.containerHeight;break;case 36:d=a.ctrlKey?t.scrollTop:e.containerHeight;break;default:return}s(t,"top",t.scrollTop-d),s(t,"left",t.scrollLeft+u),l(t),i=n(u,d),i&&a.preventDefault()}})}var o=t("../../lib/helper"),i=t("../instances"),l=t("../update-geometry"),s=t("../update-scroll");e.exports=function(t){var e=i.get(t);r(t,e)}},{"../../lib/helper":6,"../instances":18,"../update-geometry":19,"../update-scroll":20}],13:[function(t,e,n){"use strict";function r(t,e){function n(n,r){var o=t.scrollTop;if(0===n){if(!e.scrollbarYActive)return!1;if(0===o&&r>0||o>=e.contentHeight-e.containerHeight&&0>r)return!e.settings.wheelPropagation}var i=t.scrollLeft;if(0===r){if(!e.scrollbarXActive)return!1;if(0===i&&0>n||i>=e.contentWidth-e.containerWidth&&n>0)return!e.settings.wheelPropagation}return!0}function r(t){var e=t.deltaX,n=-1*t.deltaY;return("undefined"==typeof e||"undefined"==typeof n)&&(e=-1*t.wheelDeltaX/6,n=t.wheelDeltaY/6),t.deltaMode&&1===t.deltaMode&&(e*=10,n*=10),e!==e&&n!==n&&(e=0,n=t.wheelDelta),[e,n]}function i(e,n){var r=t.querySelector("textarea:hover");if(r){var o=r.scrollHeight-r.clientHeight;if(o>0&&!(0===r.scrollTop&&n>0||r.scrollTop===o&&0>n))return!0;var i=r.scrollLeft-r.clientWidth;if(i>0&&!(0===r.scrollLeft&&0>e||r.scrollLeft===i&&e>0))return!0}return!1}function a(a){if(o.env.isWebKit||!t.querySelector("select:focus")){var u=r(a),d=u[0],p=u[1];i(d,p)||(c=!1,e.settings.useBothWheelAxes?e.scrollbarYActive&&!e.scrollbarXActive?(p?s(t,"top",t.scrollTop-p*e.settings.wheelSpeed):s(t,"top",t.scrollTop+d*e.settings.wheelSpeed),c=!0):e.scrollbarXActive&&!e.scrollbarYActive&&(d?s(t,"left",t.scrollLeft+d*e.settings.wheelSpeed):s(t,"left",t.scrollLeft-p*e.settings.wheelSpeed),c=!0):(s(t,"top",t.scrollTop-p*e.settings.wheelSpeed),s(t,"left",t.scrollLeft+d*e.settings.wheelSpeed)),l(t),c=c||n(d,p),c&&(a.stopPropagation(),a.preventDefault()))}}var c=!1;"undefined"!=typeof window.onwheel?e.event.bind(t,"wheel",a):"undefined"!=typeof window.onmousewheel&&e.event.bind(t,"mousewheel",a)}var o=t("../../lib/helper"),i=t("../instances"),l=t("../update-geometry"),s=t("../update-scroll");e.exports=function(t){var e=i.get(t);r(t,e)}},{"../../lib/helper":6,"../instances":18,"../update-geometry":19,"../update-scroll":20}],14:[function(t,e,n){"use strict";function r(t,e){e.event.bind(t,"scroll",function(){i(t)})}var o=t("../instances"),i=t("../update-geometry");e.exports=function(t){var e=o.get(t);r(t,e)}},{"../instances":18,"../update-geometry":19}],15:[function(t,e,n){"use strict";function r(t,e){function n(){var t=window.getSelection?window.getSelection():document.getSelection?document.getSelection():"";return 0===t.toString().length?null:t.getRangeAt(0).commonAncestorContainer}function r(){c||(c=setInterval(function(){return i.get(t)?(s(t,"top",t.scrollTop+u.top),s(t,"left",t.scrollLeft+u.left),void l(t)):void clearInterval(c)},50))}function a(){c&&(clearInterval(c),c=null),o.stopScrolling(t)}var c=null,u={top:0,left:0},d=!1;e.event.bind(e.ownerDocument,"selectionchange",function(){t.contains(n())?d=!0:(d=!1,a())}),e.event.bind(window,"mouseup",function(){d&&(d=!1,a())}),e.event.bind(window,"mousemove",function(e){if(d){var n={x:e.pageX,y:e.pageY},i={left:t.offsetLeft,right:t.offsetLeft+t.offsetWidth,top:t.offsetTop,bottom:t.offsetTop+t.offsetHeight};n.x<i.left+3?(u.left=-5,o.startScrolling(t,"x")):n.x>i.right-3?(u.left=5,o.startScrolling(t,"x")):u.left=0,n.y<i.top+3?(i.top+3-n.y<5?u.top=-5:u.top=-20,o.startScrolling(t,"y")):n.y>i.bottom-3?(n.y-i.bottom+3<5?u.top=5:u.top=20,o.startScrolling(t,"y")):u.top=0,0===u.top&&0===u.left?a():r()}})}var o=t("../../lib/helper"),i=t("../instances"),l=t("../update-geometry"),s=t("../update-scroll");e.exports=function(t){var e=i.get(t);r(t,e)}},{"../../lib/helper":6,"../instances":18,"../update-geometry":19,"../update-scroll":20}],16:[function(t,e,n){"use strict";function r(t,e,n,r){function s(n,r){var o=t.scrollTop,i=t.scrollLeft,l=Math.abs(n),s=Math.abs(r);if(s>l){if(0>r&&o===e.contentHeight-e.containerHeight||r>0&&0===o)return!e.settings.swipePropagation}else if(l>s&&(0>n&&i===e.contentWidth-e.containerWidth||n>0&&0===i))return!e.settings.swipePropagation;return!0}function a(e,n){l(t,"top",t.scrollTop-n),l(t,"left",t.scrollLeft-e),i(t)}function c(){Y=!0}function u(){Y=!1}function d(t){return t.targetTouches?t.targetTouches[0]:t}function p(t){return t.targetTouches&&1===t.targetTouches.length?!0:t.pointerType&&"mouse"!==t.pointerType&&t.pointerType!==t.MSPOINTER_TYPE_MOUSE?!0:!1}function f(t){if(p(t)){w=!0;var e=d(t);b.pageX=e.pageX,b.pageY=e.pageY,g=(new Date).getTime(),null!==y&&clearInterval(y),t.stopPropagation()}}function h(t){if(!Y&&w&&p(t)){var e=d(t),n={pageX:e.pageX,pageY:e.pageY},r=n.pageX-b.pageX,o=n.pageY-b.pageY;a(r,o),b=n;var i=(new Date).getTime(),l=i-g;l>0&&(m.x=r/l,m.y=o/l,g=i),s(r,o)&&(t.stopPropagation(),t.preventDefault())}}function v(){!Y&&w&&(w=!1,clearInterval(y),y=setInterval(function(){return o.get(t)?Math.abs(m.x)<.01&&Math.abs(m.y)<.01?void clearInterval(y):(a(30*m.x,30*m.y),m.x*=.8,void(m.y*=.8)):void clearInterval(y)},10))}var b={},g=0,m={},y=null,Y=!1,w=!1;n&&(e.event.bind(window,"touchstart",c),e.event.bind(window,"touchend",u),e.event.bind(t,"touchstart",f),e.event.bind(t,"touchmove",h),e.event.bind(t,"touchend",v)),r&&(window.PointerEvent?(e.event.bind(window,"pointerdown",c),e.event.bind(window,"pointerup",u),e.event.bind(t,"pointerdown",f),e.event.bind(t,"pointermove",h),e.event.bind(t,"pointerup",v)):window.MSPointerEvent&&(e.event.bind(window,"MSPointerDown",c),e.event.bind(window,"MSPointerUp",u),e.event.bind(t,"MSPointerDown",f),e.event.bind(t,"MSPointerMove",h),e.event.bind(t,"MSPointerUp",v)))}var o=t("../instances"),i=t("../update-geometry"),l=t("../update-scroll");e.exports=function(t,e,n){var i=o.get(t);r(t,i,e,n)}},{"../instances":18,"../update-geometry":19,"../update-scroll":20}],17:[function(t,e,n){"use strict";var r=t("../lib/class"),o=t("../lib/helper"),i=t("./instances"),l=t("./update-geometry"),s=t("./handler/click-rail"),a=t("./handler/drag-scrollbar"),c=t("./handler/keyboard"),u=t("./handler/mouse-wheel"),d=t("./handler/native-scroll"),p=t("./handler/selection"),f=t("./handler/touch");e.exports=function(t,e){e="object"==typeof e?e:{},r.add(t,"ps-container");var n=i.add(t);n.settings=o.extend(n.settings,e),s(t),a(t),u(t),d(t),n.settings.useSelectionScroll&&p(t),(o.env.supportsTouch||o.env.supportsIePointer)&&f(t,o.env.supportsTouch,o.env.supportsIePointer),n.settings.useKeyboard&&c(t),l(t)}},{"../lib/class":2,"../lib/helper":6,"./handler/click-rail":10,"./handler/drag-scrollbar":11,"./handler/keyboard":12,"./handler/mouse-wheel":13,"./handler/native-scroll":14,"./handler/selection":15,"./handler/touch":16,"./instances":18,"./update-geometry":19}],18:[function(t,e,n){"use strict";function r(t){var e=this;e.settings=d.clone(a),e.containerWidth=null,e.containerHeight=null,e.contentWidth=null,e.contentHeight=null,e.isRtl="rtl"===s.css(t,"direction"),e.isNegativeScroll=function(){var e=t.scrollLeft,n=null;return t.scrollLeft=-1,n=t.scrollLeft<0,t.scrollLeft=e,n}(),e.negativeScrollAdjustment=e.isNegativeScroll?t.scrollWidth-t.clientWidth:0,e.event=new c,e.ownerDocument=t.ownerDocument||document,e.scrollbarXRail=s.appendTo(s.e("div","ps-scrollbar-x-rail"),t),e.scrollbarX=s.appendTo(s.e("div","ps-scrollbar-x"),e.scrollbarXRail),e.scrollbarXActive=null,e.scrollbarXWidth=null,e.scrollbarXLeft=null,e.scrollbarXBottom=d.toInt(s.css(e.scrollbarXRail,"bottom")),e.isScrollbarXUsingBottom=e.scrollbarXBottom===e.scrollbarXBottom,e.scrollbarXTop=e.isScrollbarXUsingBottom?null:d.toInt(s.css(e.scrollbarXRail,"top")),e.railBorderXWidth=d.toInt(s.css(e.scrollbarXRail,"borderLeftWidth"))+d.toInt(s.css(e.scrollbarXRail,"borderRightWidth")),s.css(e.scrollbarXRail,"display","block"),e.railXMarginWidth=d.toInt(s.css(e.scrollbarXRail,"marginLeft"))+d.toInt(s.css(e.scrollbarXRail,"marginRight")),s.css(e.scrollbarXRail,"display",""),e.railXWidth=null,e.railXRatio=null,e.scrollbarYRail=s.appendTo(s.e("div","ps-scrollbar-y-rail"),t),e.scrollbarY=s.appendTo(s.e("div","ps-scrollbar-y"),e.scrollbarYRail),e.scrollbarYActive=null,e.scrollbarYHeight=null,e.scrollbarYTop=null,e.scrollbarYRight=d.toInt(s.css(e.scrollbarYRail,"right")),e.isScrollbarYUsingRight=e.scrollbarYRight===e.scrollbarYRight,e.scrollbarYLeft=e.isScrollbarYUsingRight?null:d.toInt(s.css(e.scrollbarYRail,"left")),e.scrollbarYOuterWidth=e.isRtl?d.outerWidth(e.scrollbarY):null,e.railBorderYWidth=d.toInt(s.css(e.scrollbarYRail,"borderTopWidth"))+d.toInt(s.css(e.scrollbarYRail,"borderBottomWidth")),s.css(e.scrollbarYRail,"display","block"),e.railYMarginHeight=d.toInt(s.css(e.scrollbarYRail,"marginTop"))+d.toInt(s.css(e.scrollbarYRail,"marginBottom")),s.css(e.scrollbarYRail,"display",""),e.railYHeight=null,e.railYRatio=null}function o(t){return"undefined"==typeof t.dataset?t.getAttribute("data-ps-id"):t.dataset.psId}function i(t,e){"undefined"==typeof t.dataset?t.setAttribute("data-ps-id",e):t.dataset.psId=e}function l(t){"undefined"==typeof t.dataset?t.removeAttribute("data-ps-id"):delete t.dataset.psId}var s=t("../lib/dom"),a=t("./default-setting"),c=t("../lib/event-manager"),u=t("../lib/guid"),d=t("../lib/helper"),p={};n.add=function(t){var e=u();return i(t,e),p[e]=new r(t),p[e]},n.remove=function(t){delete p[o(t)],l(t)},n.get=function(t){return p[o(t)]}},{"../lib/dom":3,"../lib/event-manager":4,"../lib/guid":5,"../lib/helper":6,"./default-setting":8}],19:[function(t,e,n){"use strict";function r(t,e){return t.settings.minScrollbarLength&&(e=Math.max(e,t.settings.minScrollbarLength)),t.settings.maxScrollbarLength&&(e=Math.min(e,t.settings.maxScrollbarLength)),e}function o(t,e){var n={width:e.railXWidth};e.isRtl?n.left=e.negativeScrollAdjustment+t.scrollLeft+e.containerWidth-e.contentWidth:n.left=t.scrollLeft,e.isScrollbarXUsingBottom?n.bottom=e.scrollbarXBottom-t.scrollTop:n.top=e.scrollbarXTop+t.scrollTop,l.css(e.scrollbarXRail,n);var r={top:t.scrollTop,height:e.railYHeight};e.isScrollbarYUsingRight?e.isRtl?r.right=e.contentWidth-(e.negativeScrollAdjustment+t.scrollLeft)-e.scrollbarYRight-e.scrollbarYOuterWidth:r.right=e.scrollbarYRight-t.scrollLeft:e.isRtl?r.left=e.negativeScrollAdjustment+t.scrollLeft+2*e.containerWidth-e.contentWidth-e.scrollbarYLeft-e.scrollbarYOuterWidth:r.left=e.scrollbarYLeft+t.scrollLeft,l.css(e.scrollbarYRail,r),l.css(e.scrollbarX,{left:e.scrollbarXLeft,width:e.scrollbarXWidth-e.railBorderXWidth}),l.css(e.scrollbarY,{top:e.scrollbarYTop,height:e.scrollbarYHeight-e.railBorderYWidth})}var i=t("../lib/class"),l=t("../lib/dom"),s=t("../lib/helper"),a=t("./instances"),c=t("./update-scroll");e.exports=function(t){var e=a.get(t);e.containerWidth=t.clientWidth,e.containerHeight=t.clientHeight,e.contentWidth=t.scrollWidth,e.contentHeight=t.scrollHeight;var n;t.contains(e.scrollbarXRail)||(n=l.queryChildren(t,".ps-scrollbar-x-rail"),n.length>0&&n.forEach(function(t){l.remove(t)}),l.appendTo(e.scrollbarXRail,t)),t.contains(e.scrollbarYRail)||(n=l.queryChildren(t,".ps-scrollbar-y-rail"),n.length>0&&n.forEach(function(t){l.remove(t)}),l.appendTo(e.scrollbarYRail,t)),!e.settings.suppressScrollX&&e.containerWidth+e.settings.scrollXMarginOffset<e.contentWidth?(e.scrollbarXActive=!0,e.railXWidth=e.containerWidth-e.railXMarginWidth,e.railXRatio=e.containerWidth/e.railXWidth,e.scrollbarXWidth=r(e,s.toInt(e.railXWidth*e.containerWidth/e.contentWidth)),e.scrollbarXLeft=s.toInt((e.negativeScrollAdjustment+t.scrollLeft)*(e.railXWidth-e.scrollbarXWidth)/(e.contentWidth-e.containerWidth))):(e.scrollbarXActive=!1,e.scrollbarXWidth=0,e.scrollbarXLeft=0,t.scrollLeft=0),!e.settings.suppressScrollY&&e.containerHeight+e.settings.scrollYMarginOffset<e.contentHeight?(e.scrollbarYActive=!0,e.railYHeight=e.containerHeight-e.railYMarginHeight,e.railYRatio=e.containerHeight/e.railYHeight,e.scrollbarYHeight=r(e,s.toInt(e.railYHeight*e.containerHeight/e.contentHeight)),e.scrollbarYTop=s.toInt(t.scrollTop*(e.railYHeight-e.scrollbarYHeight)/(e.contentHeight-e.containerHeight))):(e.scrollbarYActive=!1,e.scrollbarYHeight=0,e.scrollbarYTop=0,c(t,"top",0)),e.scrollbarXLeft>=e.railXWidth-e.scrollbarXWidth&&(e.scrollbarXLeft=e.railXWidth-e.scrollbarXWidth),e.scrollbarYTop>=e.railYHeight-e.scrollbarYHeight&&(e.scrollbarYTop=e.railYHeight-e.scrollbarYHeight),o(t,e),i[e.scrollbarXActive?"add":"remove"](t,"ps-active-x"),i[e.scrollbarYActive?"add":"remove"](t,"ps-active-y")}},{"../lib/class":2,"../lib/dom":3,"../lib/helper":6,"./instances":18,"./update-scroll":20}],20:[function(t,e,n){"use strict";var r,o,i=t("./instances"),l=document.createEvent("Event"),s=document.createEvent("Event"),a=document.createEvent("Event"),c=document.createEvent("Event"),u=document.createEvent("Event"),d=document.createEvent("Event"),p=document.createEvent("Event"),f=document.createEvent("Event"),h=document.createEvent("Event"),v=document.createEvent("Event");l.initEvent("ps-scroll-up",!0,!0),s.initEvent("ps-scroll-down",!0,!0),a.initEvent("ps-scroll-left",!0,!0),c.initEvent("ps-scroll-right",!0,!0),u.initEvent("ps-scroll-y",!0,!0),d.initEvent("ps-scroll-x",!0,!0),p.initEvent("ps-x-reach-start",!0,!0),f.initEvent("ps-x-reach-end",!0,!0),h.initEvent("ps-y-reach-start",!0,!0),v.initEvent("ps-y-reach-end",!0,!0),e.exports=function(t,e,n){if("undefined"==typeof t)throw"You must provide an element to the update-scroll function";if("undefined"==typeof e)throw"You must provide an axis to the update-scroll function";if("undefined"==typeof n)throw"You must provide a value to the update-scroll function";if("top"===e&&0>=n)return t.scrollTop=0,void t.dispatchEvent(h);if("left"===e&&0>=n)return t.scrollLeft=0,void t.dispatchEvent(p);var b=i.get(t);return"top"===e&&n>b.contentHeight-b.containerHeight?(t.scrollTop=b.contentHeight-b.containerHeight,void t.dispatchEvent(v)):"left"===e&&n>b.contentWidth-b.containerWidth?(t.scrollLeft=b.contentWidth-b.containerWidth,void t.dispatchEvent(f)):(r||(r=t.scrollTop),o||(o=t.scrollLeft),"top"===e&&r>n&&t.dispatchEvent(l),"top"===e&&n>r&&t.dispatchEvent(s),"left"===e&&o>n&&t.dispatchEvent(a),"left"===e&&n>o&&t.dispatchEvent(c),"top"===e&&(t.scrollTop=r=n,t.dispatchEvent(u)),void("left"===e&&(t.scrollLeft=o=n,t.dispatchEvent(d))))}},{"./instances":18}],21:[function(t,e,n){"use strict";var r=t("../lib/dom"),o=t("../lib/helper"),i=t("./instances"),l=t("./update-geometry");e.exports=function(t){var e=i.get(t);e&&(e.negativeScrollAdjustment=e.isNegativeScroll?t.scrollWidth-t.clientWidth:0,r.css(e.scrollbarXRail,"display","block"),r.css(e.scrollbarYRail,"display","block"),e.railXMarginWidth=o.toInt(r.css(e.scrollbarXRail,"marginLeft"))+o.toInt(r.css(e.scrollbarXRail,"marginRight")),e.railYMarginHeight=o.toInt(r.css(e.scrollbarYRail,"marginTop"))+o.toInt(r.css(e.scrollbarYRail,"marginBottom")),r.css(e.scrollbarXRail,"display","none"),r.css(e.scrollbarYRail,"display","none"),l(t),r.css(e.scrollbarXRail,"display",""),r.css(e.scrollbarYRail,"display",""))}},{"../lib/dom":3,"../lib/helper":6,"./instances":18,"./update-geometry":19}]},{},[1]);
\ No newline at end of file diff --git a/web/templates/claim_account.html b/web/templates/claim_account.html index bcf63fd95..2a9126d1b 100644 --- a/web/templates/claim_account.html +++ b/web/templates/claim_account.html @@ -7,7 +7,7 @@ <div class="inner__wrap"> <div class="row content"> <div class="signup-header"> - <a href="/{{.Props.TeamName}}">{{.Props.TeamDisplayName}}</a> + <a href="/{{.Props.TeamName}}"><span class='fa fa-chevron-left'></span>{{ .ClientCfg.HeaderBack }}</a> </div> <div class="col-sm-12"> <div class="signup-team__container"> diff --git a/web/templates/docs.html b/web/templates/docs.html index 1a20580fb..dc18e5cb6 100644 --- a/web/templates/docs.html +++ b/web/templates/docs.html @@ -7,7 +7,7 @@ <div class="inner__wrap"> <div class="row content"> <div class="signup-header"> - <a href="/">{{ .ClientCfg.SiteName }}</a> + <a href="/"><span class='fa fa-chevron-left'></span>{{ .ClientCfg.HeaderBack }}</a> </div> <div class="col-sm-12"> <div class="docs__page" id="docs"></div> diff --git a/web/templates/find_team.html b/web/templates/find_team.html index 15b8bf463..b7e1d7eca 100644 --- a/web/templates/find_team.html +++ b/web/templates/find_team.html @@ -7,7 +7,7 @@ <div class="inner__wrap"> <div class="row content"> <div class="signup-header"> - <a href="/">{{ .ClientCfg.SiteName }}</a> + <a href="/"><span class='fa fa-chevron-left'></span>{{ .ClientCfg.HeaderBack }}</a> </div> <div class="col-sm-12"> <div class="signup-team__container"> diff --git a/web/templates/head.html b/web/templates/head.html index 94a86e3dd..dadd148c1 100644 --- a/web/templates/head.html +++ b/web/templates/head.html @@ -54,7 +54,7 @@ <script src="/static/js/bootstrap-colorpicker.min.js"></script> <script src="/static/js/react-bootstrap-0.28.1.js"></script> <script src="/static/js/velocity.min.js"></script> - <script src="/static/js/perfect-scrollbar-0.6.7.jquery.min.js"></script> + <script src="/static/js/perfect-scrollbar-0.6.10.jquery.min.js"></script> <script src="/static/js/jquery-dragster/jquery.dragster.js"></script> <script src="/static/js/babel-polyfill-6.1.18.min.js"></script> <script src="/static/js/katex.min.js"></script> diff --git a/web/templates/login.html b/web/templates/login.html index be5e6bf4f..88540a906 100644 --- a/web/templates/login.html +++ b/web/templates/login.html @@ -7,7 +7,7 @@ <div class="inner__wrap"> <div class="row content"> <div class="signup-header"> - <a href="/">{{ .ClientCfg.SiteName }}</a> + <a href="/"><span class='fa fa-chevron-left'></span>{{ .ClientCfg.HeaderBack }}</a> </div> <div class="col-sm-12"> <div id="login"></div> diff --git a/web/templates/password_reset.html b/web/templates/password_reset.html index df82285ef..e68f8b693 100644 --- a/web/templates/password_reset.html +++ b/web/templates/password_reset.html @@ -7,7 +7,7 @@ <div class="inner__wrap"> <div class="row content"> <div class="signup-header"> - <a href="/{{.Props.TeamName}}">{{.Props.TeamDisplayName}}</a> + <a href="/{{.Props.TeamName}}"><span class='fa fa-chevron-left'></span>{{ .ClientCfg.HeaderBack }}</a> </div> <div class="col-sm-12"> <div class="signup-team__container"> diff --git a/web/templates/signup_team_complete.html b/web/templates/signup_team_complete.html index 4b179b1e1..3873d8978 100644 --- a/web/templates/signup_team_complete.html +++ b/web/templates/signup_team_complete.html @@ -6,6 +6,9 @@ <div class="container-fluid"> <div class="inner__wrap"> <div class="row content"> + <div class="signup-header"> + <a href="/{{.Props.TeamName}}"><span class='fa fa-chevron-left'></span>{{ .ClientCfg.HeaderBack }}</a> + </div> <div class="col-sm-12"> <div class="signup-team__container"> <div id="signup-team-complete"></div> diff --git a/web/templates/signup_team_confirm.html b/web/templates/signup_team_confirm.html index d16861808..31f1ba95b 100644 --- a/web/templates/signup_team_confirm.html +++ b/web/templates/signup_team_confirm.html @@ -6,6 +6,9 @@ <div class="container-fluid"> <div class="inner__wrap"> <div class="row content"> + <div class="signup-header"> + <a href="/{{.Props.TeamName}}"><span class='fa fa-chevron-left'></span>{{ .ClientCfg.HeaderBack }}</a> + </div> <div class="col-sm-12"> <div id="signup-team-confirm"></div> </div> diff --git a/web/templates/signup_user_complete.html b/web/templates/signup_user_complete.html index 2400b7b77..937a89dd2 100644 --- a/web/templates/signup_user_complete.html +++ b/web/templates/signup_user_complete.html @@ -6,6 +6,9 @@ <div class="container-fluid"> <div class="inner__wrap"> <div class="row content"> + <div class="signup-header"> + <a href="/{{.Props.TeamName}}"><span class='fa fa-chevron-left'></span>{{ .ClientCfg.HeaderBack }}</a> + </div> <div class="col-sm-12"> <div class="signup-team__container padding--less"> <div id="signup-user-complete"></div> diff --git a/web/templates/verify.html b/web/templates/verify.html index bab329c7d..2e5496d7a 100644 --- a/web/templates/verify.html +++ b/web/templates/verify.html @@ -7,7 +7,7 @@ <div class="inner__wrap"> <div class="row content"> <div class="signup-header"> - <a href="/{{.Props.TeamName}}">{{.Props.TeamDisplayName}}</a> + <a href="/{{.Props.TeamName}}"><span class='fa fa-chevron-left'></span>{{ .ClientCfg.HeaderBack }}</a> </div> <div class="col-sm-12"> <div class="signup-team__container"> diff --git a/web/web.go b/web/web.go index efe0e6b13..09450b976 100644 --- a/web/web.go +++ b/web/web.go @@ -54,6 +54,7 @@ func (me *HtmlTemplatePage) Render(c *api.Context, w http.ResponseWriter) { me.Props["Locale"] = me.Locale me.SessionTokenIndex = c.SessionTokenIndex + me.ClientCfg["HeaderBack"] = c.T("web.header.back") me.ClientCfg["FooterHelp"] = c.T("web.footer.help") me.ClientCfg["FooterTerms"] = c.T("web.footer.terms") me.ClientCfg["FooterPrivacy"] = c.T("web.footer.privacy") |