Browse Source

Merge remote-tracking branch 'oficial/1.10.x' into t0001

nosolored 8 years ago
parent
commit
42a88a8629
100 changed files with 3871 additions and 1578 deletions
  1. 1 0
      .scrutinizer.yml
  2. 19 16
      .travis.yml
  3. 1 1
      README.md
  4. 20 20
      app/Resources/public/assets/ckeditor/plugins/scayt/CHANGELOG.md
  5. 28 28
      app/Resources/public/assets/ckeditor/plugins/scayt/LICENSE.md
  6. 25 0
      app/Resources/public/assets/ckeditor/plugins/scayt/README.md
  7. 573 19
      app/Resources/public/assets/ckeditor/plugins/scayt/dialogs/options.js
  8. 71 71
      app/Resources/public/assets/ckeditor/plugins/scayt/dialogs/toolbar.css
  9. BIN
      app/Resources/public/assets/ckeditor/plugins/scayt/icons/hidpi/scayt.png
  10. BIN
      app/Resources/public/assets/ckeditor/plugins/scayt/icons/scayt.png
  11. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/af.js
  12. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/ar.js
  13. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/bg.js
  14. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/bn.js
  15. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/bs.js
  16. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/ca.js
  17. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/cs.js
  18. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/cy.js
  19. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/da.js
  20. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/de.js
  21. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/el.js
  22. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/en-au.js
  23. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/en-ca.js
  24. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/en-gb.js
  25. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/en.js
  26. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/eo.js
  27. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/es.js
  28. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/et.js
  29. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/eu.js
  30. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/fa.js
  31. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/fi.js
  32. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/fo.js
  33. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/fr-ca.js
  34. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/fr.js
  35. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/gl.js
  36. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/gu.js
  37. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/he.js
  38. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/hi.js
  39. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/hr.js
  40. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/hu.js
  41. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/is.js
  42. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/it.js
  43. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/ja.js
  44. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/ka.js
  45. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/km.js
  46. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/ko.js
  47. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/ku.js
  48. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/lt.js
  49. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/lv.js
  50. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/mk.js
  51. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/mn.js
  52. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/ms.js
  53. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/nb.js
  54. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/nl.js
  55. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/no.js
  56. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/pl.js
  57. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/pt-br.js
  58. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/pt.js
  59. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/ro.js
  60. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/ru.js
  61. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/sk.js
  62. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/sl.js
  63. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/sr-latn.js
  64. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/sr.js
  65. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/sv.js
  66. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/th.js
  67. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/tr.js
  68. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/ug.js
  69. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/uk.js
  70. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/vi.js
  71. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/zh-cn.js
  72. 13 0
      app/Resources/public/assets/ckeditor/plugins/scayt/lang/zh.js
  73. 1877 0
      app/Resources/public/assets/ckeditor/plugins/scayt/plugin.js
  74. 38 166
      app/Resources/public/css/chat.css
  75. 0 1
      app/config/mail.conf.dist.php
  76. 4 1
      documentation/installation_guide.html
  77. 7 6
      documentation/installation_guide_es_ES.html
  78. 4 2
      documentation/installation_guide_fr_FR.html
  79. 11 8
      documentation/optimization.html
  80. 0 1
      index.php
  81. 1 1
      main/admin/add_users_to_usergroup.php
  82. 31 3
      main/admin/index.php
  83. 40 46
      main/admin/subscribe_user2course.php
  84. 204 0
      main/admin/teachers_time_by_session_report.php
  85. 1 1
      main/auth/courses.php
  86. 10 3
      main/auth/courses_controller.php
  87. 11 6
      main/auth/external_login/newUser.ldap.php
  88. 39 73
      main/chat/chat.php
  89. 0 217
      main/chat/chat_chat.php
  90. 0 242
      main/chat/chat_functions.lib.php
  91. 0 126
      main/chat/chat_hidden.php
  92. 0 128
      main/chat/chat_message.php
  93. 0 162
      main/chat/chat_whoisonline.php
  94. 0 17
      main/chat/footer_frame.inc.php
  95. 0 147
      main/chat/header_frame.inc.php
  96. 2 1
      main/course_info/tools.php
  97. 2 2
      main/course_progress/index.php
  98. 2 7
      main/course_progress/thematic.php
  99. 36 2
      main/course_progress/thematic_advance.php
  100. 7 54
      main/course_progress/thematic_controller.php

+ 1 - 0
.scrutinizer.yml

@@ -21,6 +21,7 @@ filter:
         - web/*
         - vendor/*
         - main/admin/db.php
+        - app/Migrations/*
 checks:
     php:
         code_rating: true

+ 19 - 16
.travis.yml

@@ -12,6 +12,18 @@ before_install:
   - sudo apt-get update -qq
   - sudo apt-get install -qq mysql-server
   - sudo apt-get install -qq apache2 libapache2-mod-fastcgi
+  # enable php-fpm
+  - sudo cp ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf.default ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf
+  - sudo a2enmod rewrite actions fastcgi alias
+  - echo "cgi.fix_pathinfo = 1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
+  - echo "memory_limit = 2G" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
+  - echo "phar.readonly = 0" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
+  - echo "date.timezone = Europe/Paris" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
+  - ~/.phpenv/versions/$(phpenv version-name)/sbin/php-fpm
+  # configure apache virtual hosts
+  - sudo cp -f tests/travis-apache /etc/apache2/sites-available/default
+  - sudo sed -e "s?%TRAVIS_BUILD_DIR%?$(pwd)?g" --in-place /etc/apache2/sites-available/default
+  - sudo service apache2 restart
   # Install additional PHP packages (check http://docs.travis-ci.com/user/ci-environment/#CI-environment-OS
   # for pre-installed packages)
   #- sudo apt-get install -qq php5-imagick
@@ -19,12 +31,12 @@ before_install:
   # php is compiled with --enable-fpm, so no install of FPM is needed.
   # However, not installing it generates errors with service php5-fpm restart
   # further down (need to use php-fpm without 5)
-  - sudo apt-get install -qq php5-cli php5-fpm
+  #- sudo apt-get install -qq php5-cli php5-fpm
 
 before_script:
-  - php5 -v
-  - php5 -m
-  - composer self-update
+  #- which composer
+  #- php -d memory_limit=2G /usr/bin/composer update
+  #- php -d memory_limit=2G /home/travis/.phpenv/shims/composer update
   # Previously, fxp/composer-asset-plugin was required but was causing a lot of trouble updating. Now it's disabled.
   #- composer global require "fxp/composer-asset-plugin:1.0.3"
   # You can either use the composer install method and face the Github limit
@@ -43,23 +55,14 @@ before_script:
   # Continue...
   - phpenv config-add tests/travis-php-config.ini
   # enable php-fpm
-  - sudo /etc/init.d/php5-fpm stop
-  - sudo cp ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf.default ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf
-  - sudo a2enmod rewrite actions fastcgi alias
-  - echo "cgi.fix_pathinfo = 1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
-  - ~/.phpenv/versions/$(phpenv version-name)/sbin/php-fpm
   # configure apache virtual hosts
-  - sudo cp -f tests/travis-apache /etc/apache2/sites-available/default
-  - sudo sed -e "s?%TRAVIS_BUILD_DIR%?$(pwd)?g" --in-place /etc/apache2/sites-available/default
-  - sudo service apache2 restart
-  - sudo service php5-fpm restart
-  - php5 -v
+  - php -v
   # install Chash, a database, and then install Chamilo
   - git clone https://github.com/chamilo/chash
   - cd chash
   - composer install
   - composer update
-  - php5 -d phar.readonly=0 createPhar.php
+  - php -d phar.readonly=0 createPhar.php
   - chmod +x chash.phar
   - sudo mv chash.phar /usr/local/bin/chash
   #- cd ..
@@ -74,7 +77,7 @@ before_script:
   - cd /home/travis/build/chamilo/chamilo-lms
   # There's an issue with Chash, starting in version 1.10, whereby PHP CLI on Travis-ci is PHP5.3, whatever the version you ask for.
   # This effectively breaks the installer and renders these tests useless. We are looking for a solution (for example using containers)
-  - sudo chash chash:chamilo_install --no-interaction --sitename="Chamilo" --site_url="http://localhost/" --institution="Chamilo" --institution_url="https://chamilo.org" --encrypt_method="sha1" --firstname="John" --lastname="Doe" --language="english" --driver="mysqlnd" --host="localhost" --port="3306" --dbname="chamilo" --dbuser="root" --permissions_for_new_directories="0777" --permissions_for_new_files="0666" --linux-user="www-data" --linux-group="www-data" --username="admin" --password="admin" --email="admin@example.com" --phone="555-5555" 1.10.x
+  - sudo chash chash:chamilo_install --no-interaction --sitename="Chamilo" --site_url="http://localhost/" --institution="Chamilo" --institution_url="https://chamilo.org" --encrypt_method="sha1" --firstname="John" --lastname="Doe" --language="english" --driver="pdo_mysql" --host="localhost" --port="3306" --dbname="chamilo" --dbuser="root" --permissions_for_new_directories="0777" --permissions_for_new_files="0666" --linux-user="www-data" --linux-group="www-data" --username="admin" --password="admin" --email="admin@example.com" --phone="555-5555" 1.10.x
 
 script:
   # - phpunit -c tests/phpunit

+ 1 - 1
README.md

@@ -168,7 +168,7 @@ php bin/doctrine.php migrations:execute 20150527120703 --up --configuration=app/
 
 You can also print the differences between your database and what it should be by issuing the following command from the Chamilo base folder:
 ```
-php bin/doctrine.php orm:schema:update --dump-sql
+php bin/doctrine.php orm:schema-tool:update --dump-sql
 ```
 
 ## Contributing

+ 20 - 20
app/Resources/public/assets/ckeditor/plugins/scayt/CHANGELOG.md

@@ -1,20 +1,20 @@
-SCAYT plugin for CKEditor 4 Changelog
-====================
-### CKEditor 4.5.6
-
-New Features:
-* CKEditor [language addon](http://ckeditor.com/addon/language) support
-* CKEditor [placeholder addon](http://ckeditor.com/addon/placeholder) support
-* Drag and Drop support
-* *Experimental* GRAYT functionality http://www.webspellchecker.net/samples/scayt-ckeditor-plugin.html#25
-
-Fixed issues:
-* [#98](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/98) SCAYT Affects Dialog Double Click. Fixed in SCAYT Core.
-* [#102](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/102) SCAYT Core performance enhancements
-* [#104](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/104) SCAYT's spans leak into the clipboard and after pasting
-* [#105](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/105) Javascript error fired in case of multiple instances of CKEditor in one page
-* [#107](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/107) SCAYT should not check non-editable parts of content
-* [#108](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/108) Latest SCAYT copies id of editor element to the iframe
-* SCAYT stops working when CKEditor Undo plug-in not enabled
-* Issue with pasting SCAYT markup in CKEditor
-* [#32](https://github.com/WebSpellChecker/ckeditor-plugin-wsc/issues/32) SCAYT stops working after pressing Cancel button in WSC dialog
+SCAYT plugin for CKEditor 4 Changelog
+====================
+### CKEditor 4.5.6
+
+New Features:
+* CKEditor [language addon](http://ckeditor.com/addon/language) support
+* CKEditor [placeholder addon](http://ckeditor.com/addon/placeholder) support
+* Drag and Drop support
+* *Experimental* GRAYT functionality http://www.webspellchecker.net/samples/scayt-ckeditor-plugin.html#25
+
+Fixed issues:
+* [#98](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/98) SCAYT Affects Dialog Double Click. Fixed in SCAYT Core.
+* [#102](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/102) SCAYT Core performance enhancements
+* [#104](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/104) SCAYT's spans leak into the clipboard and after pasting
+* [#105](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/105) Javascript error fired in case of multiple instances of CKEditor in one page
+* [#107](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/107) SCAYT should not check non-editable parts of content
+* [#108](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/108) Latest SCAYT copies id of editor element to the iframe
+* SCAYT stops working when CKEditor Undo plug-in not enabled
+* Issue with pasting SCAYT markup in CKEditor
+* [#32](https://github.com/WebSpellChecker/ckeditor-plugin-wsc/issues/32) SCAYT stops working after pressing Cancel button in WSC dialog

+ 28 - 28
app/Resources/public/assets/ckeditor/plugins/scayt/LICENSE.md

@@ -1,28 +1,28 @@
-Software License Agreement
-==========================
-
-**CKEditor SCAYT Plugin**
-Copyright © 2012, [CKSource](http://cksource.com) - Frederico Knabben. All rights reserved.
-
-Licensed under the terms of any of the following licenses at your choice:
-
-*   GNU General Public License Version 2 or later (the "GPL"):
-    http://www.gnu.org/licenses/gpl.html
-
-*   GNU Lesser General Public License Version 2.1 or later (the "LGPL"):
-    http://www.gnu.org/licenses/lgpl.html
-
-*   Mozilla Public License Version 1.1 or later (the "MPL"):
-    http://www.mozilla.org/MPL/MPL-1.1.html
-
-You are not required to, but if you want to explicitly declare the license you have chosen to be bound to when using, reproducing, modifying and distributing this software, just include a text file titled "legal.txt" in your version of this software, indicating your license choice.
-
-Sources of Intellectual Property Included in this plugin
---------------------------------------------------------
-
-Where not otherwise indicated, all plugin content is authored by CKSource engineers and consists of CKSource-owned intellectual property. In some specific instances, the plugin will incorporate work done by developers outside of CKSource with their express permission.
-
-Trademarks
-----------
-
-CKEditor is a trademark of CKSource - Frederico Knabben. All other brand and product names are trademarks, registered trademarks or service marks of their respective holders.
+Software License Agreement
+==========================
+
+**CKEditor SCAYT Plugin**
+Copyright © 2012, [CKSource](http://cksource.com) - Frederico Knabben. All rights reserved.
+
+Licensed under the terms of any of the following licenses at your choice:
+
+*   GNU General Public License Version 2 or later (the "GPL"):
+    http://www.gnu.org/licenses/gpl.html
+
+*   GNU Lesser General Public License Version 2.1 or later (the "LGPL"):
+    http://www.gnu.org/licenses/lgpl.html
+
+*   Mozilla Public License Version 1.1 or later (the "MPL"):
+    http://www.mozilla.org/MPL/MPL-1.1.html
+
+You are not required to, but if you want to explicitly declare the license you have chosen to be bound to when using, reproducing, modifying and distributing this software, just include a text file titled "legal.txt" in your version of this software, indicating your license choice.
+
+Sources of Intellectual Property Included in this plugin
+--------------------------------------------------------
+
+Where not otherwise indicated, all plugin content is authored by CKSource engineers and consists of CKSource-owned intellectual property. In some specific instances, the plugin will incorporate work done by developers outside of CKSource with their express permission.
+
+Trademarks
+----------
+
+CKEditor is a trademark of CKSource - Frederico Knabben. All other brand and product names are trademarks, registered trademarks or service marks of their respective holders.

+ 25 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/README.md

@@ -0,0 +1,25 @@
+CKEditor SCAYT Plugin
+=====================
+
+This plugin brings Spell Check As You Type (SCAYT) into up to CKEditor 4+.
+
+SCAYT is a "installation-less", using the web-services of [WebSpellChecker.net](http://www.webspellchecker.net/). It's an out of the box solution.
+
+Installation
+------------
+
+1. Clone/copy this repository contents in a new "plugins/scayt" folder in your CKEditor installation.
+2. Enable the "scayt" plugin in the CKEditor configuration file (config.js):
+
+        config.extraPlugins = 'scayt';
+
+That's all. SCAYT will appear on the editor toolbar and will be ready to use.
+
+License
+-------
+
+Licensed under the terms of any of the following licenses at your choice: [GPL](http://www.gnu.org/licenses/gpl.html), [LGPL](http://www.gnu.org/licenses/lgpl.html) and [MPL](http://www.mozilla.org/MPL/MPL-1.1.html).
+
+See LICENSE.md for more information.
+
+Developed in cooperation with [WebSpellChecker.net](http://www.webspellchecker.net/).

+ 573 - 19
app/Resources/public/assets/ckeditor/plugins/scayt/dialogs/options.js

@@ -1,19 +1,573 @@
-CKEDITOR.dialog.add("scaytDialog",function(c){var f=c.scayt,q='\x3cp\x3e\x3cimg src\x3d"'+f.getLogo()+'" /\x3e\x3c/p\x3e\x3cp\x3e'+f.getLocal("version")+f.getVersion()+"\x3c/p\x3e\x3cp\x3e"+f.getLocal("text_copyrights")+"\x3c/p\x3e",r=CKEDITOR.document,n={isChanged:function(){return null===this.newLang||this.currentLang===this.newLang?!1:!0},currentLang:f.getLang(),newLang:null,reset:function(){this.currentLang=f.getLang();this.newLang=null},id:"lang"},q=[{id:"options",label:f.getLocal("tab_options"),
-onShow:function(){},elements:[{type:"vbox",id:"scaytOptions",children:function(){var a=f.getApplicationConfig(),b=[],g={"ignore-all-caps-words":"label_allCaps","ignore-domain-names":"label_ignoreDomainNames","ignore-words-with-mixed-cases":"label_mixedCase","ignore-words-with-numbers":"label_mixedWithDigits"},e;for(e in a)a={type:"checkbox"},a.id=e,a.label=f.getLocal(g[e]),b.push(a);return b}(),onShow:function(){this.getChild();for(var a=c.scayt,b=0;b<this.getChild().length;b++)this.getChild()[b].setValue(a.getApplicationConfig()[this.getChild()[b].id])}}]},
-{id:"langs",label:f.getLocal("tab_languages"),elements:[{id:"leftLangColumn",type:"vbox",align:"left",widths:["100"],children:[{type:"html",id:"langBox",style:"overflow: hidden; white-space: normal;margin-bottom:15px;",html:'\x3cdiv\x3e\x3cdiv style\x3d"float:left;width:45%;margin-left:5px;" id\x3d"left-col-'+c.name+'"\x3e\x3c/div\x3e\x3cdiv style\x3d"float:left;width:45%;margin-left:15px;" id\x3d"right-col-'+c.name+'"\x3e\x3c/div\x3e\x3c/div\x3e',onShow:function(){var a=c.scayt.getLang();r.getById("scaytLang_"+
-c.name+"_"+a).$.checked=!0}},{type:"html",id:"graytLanguagesHint",html:'\x3cdiv style\x3d"margin:5px auto; width:95%;white-space:normal;" id\x3d"'+c.name+'graytLanguagesHint"\x3e\x3cspan style\x3d"width:10px;height:10px;display: inline-block; background:#02b620;vertical-align:top;margin-top:2px;"\x3e\x3c/span\x3e - This languages are supported by Grammar As You Type(GRAYT).\x3c/div\x3e',onShow:function(){var a=r.getById(c.name+"graytLanguagesHint");c.config.grayt_autoStartup||(a.$.style.display="none")}}]}]},
-{id:"dictionaries",label:f.getLocal("tab_dictionaries"),elements:[{type:"vbox",id:"rightCol_col__left",children:[{type:"html",id:"dictionaryNote",html:""},{type:"text",id:"dictionaryName",label:f.getLocal("label_fieldNameDic")||"Dictionary name",onShow:function(a){var b=a.sender,g=c.scayt;setTimeout(function(){b.getContentElement("dictionaries","dictionaryNote").getElement().setText("");null!=g.getUserDictionaryName()&&""!=g.getUserDictionaryName()&&b.getContentElement("dictionaries","dictionaryName").setValue(g.getUserDictionaryName())},
-0)}},{type:"hbox",id:"notExistDic",align:"left",style:"width:auto;",widths:["50%","50%"],children:[{type:"button",id:"createDic",label:f.getLocal("btn_createDic"),title:f.getLocal("btn_createDic"),onClick:function(){var a=this.getDialog(),b=p,g=c.scayt,e=a.getContentElement("dictionaries","dictionaryName").getValue();g.createUserDictionary(e,function(d){d.error||b.toggleDictionaryButtons.call(a,!0);d.dialog=a;d.command="create";d.name=e;c.fire("scaytUserDictionaryAction",d)},function(d){d.dialog=
-a;d.command="create";d.name=e;c.fire("scaytUserDictionaryActionError",d)})}},{type:"button",id:"restoreDic",label:f.getLocal("btn_restoreDic"),title:f.getLocal("btn_restoreDic"),onClick:function(){var a=this.getDialog(),b=c.scayt,g=p,e=a.getContentElement("dictionaries","dictionaryName").getValue();b.restoreUserDictionary(e,function(d){d.dialog=a;d.error||g.toggleDictionaryButtons.call(a,!0);d.command="restore";d.name=e;c.fire("scaytUserDictionaryAction",d)},function(d){d.dialog=a;d.command="restore";
-d.name=e;c.fire("scaytUserDictionaryActionError",d)})}}]},{type:"hbox",id:"existDic",align:"left",style:"width:auto;",widths:["50%","50%"],children:[{type:"button",id:"removeDic",label:f.getLocal("btn_deleteDic"),title:f.getLocal("btn_deleteDic"),onClick:function(){var a=this.getDialog(),b=c.scayt,g=p,e=a.getContentElement("dictionaries","dictionaryName"),d=e.getValue();b.removeUserDictionary(d,function(b){e.setValue("");b.error||g.toggleDictionaryButtons.call(a,!1);b.dialog=a;b.command="remove";
-b.name=d;c.fire("scaytUserDictionaryAction",b)},function(b){b.dialog=a;b.command="remove";b.name=d;c.fire("scaytUserDictionaryActionError",b)})}},{type:"button",id:"renameDic",label:f.getLocal("btn_renameDic"),title:f.getLocal("btn_renameDic"),onClick:function(){var a=this.getDialog(),b=c.scayt,g=a.getContentElement("dictionaries","dictionaryName").getValue();b.renameUserDictionary(g,function(b){b.dialog=a;b.command="rename";b.name=g;c.fire("scaytUserDictionaryAction",b)},function(b){b.dialog=a;b.command=
-"rename";b.name=g;c.fire("scaytUserDictionaryActionError",b)})}}]},{type:"html",id:"dicInfo",html:'\x3cdiv id\x3d"dic_info_editor1" style\x3d"margin:5px auto; width:95%;white-space:normal;"\x3e'+f.getLocal("text_descriptionDic")+"\x3c/div\x3e"}]}]},{id:"about",label:f.getLocal("tab_about"),elements:[{type:"html",id:"about",style:"margin: 5px 5px;",html:'\x3cdiv\x3e\x3cdiv id\x3d"scayt_about_"\x3e'+q+"\x3c/div\x3e\x3c/div\x3e"}]}];c.on("scaytUserDictionaryAction",function(a){var b=SCAYT.prototype.UILib,
-g=a.data.dialog,e=g.getContentElement("dictionaries","dictionaryNote").getElement(),d=a.editor.scayt,c;void 0===a.data.error?(c=d.getLocal("message_success_"+a.data.command+"Dic"),c=c.replace("%s",a.data.name),e.setText(c),b.css(e.$,{color:"blue"})):(""===a.data.name?e.setText(d.getLocal("message_info_emptyDic")):(c=d.getLocal("message_error_"+a.data.command+"Dic"),c=c.replace("%s",a.data.name),e.setText(c)),b.css(e.$,{color:"red"}),null!=d.getUserDictionaryName()&&""!=d.getUserDictionaryName()?g.getContentElement("dictionaries",
-"dictionaryName").setValue(d.getUserDictionaryName()):g.getContentElement("dictionaries","dictionaryName").setValue(""))});c.on("scaytUserDictionaryActionError",function(a){var b=SCAYT.prototype.UILib,c=a.data.dialog,e=c.getContentElement("dictionaries","dictionaryNote").getElement(),d=a.editor.scayt,f;""===a.data.name?e.setText(d.getLocal("message_info_emptyDic")):(f=d.getLocal("message_error_"+a.data.command+"Dic"),f=f.replace("%s",a.data.name),e.setText(f));b.css(e.$,{color:"red"});null!=d.getUserDictionaryName()&&
-""!=d.getUserDictionaryName()?c.getContentElement("dictionaries","dictionaryName").setValue(d.getUserDictionaryName()):c.getContentElement("dictionaries","dictionaryName").setValue("")});var p={title:f.getLocal("text_title"),resizable:CKEDITOR.DIALOG_RESIZE_BOTH,minWidth:340,minHeight:260,onLoad:function(){if(0!=c.config.scayt_uiTabs[1]){var a=p,b=a.getLangBoxes.call(this);b.getParent().setStyle("white-space","normal");a.renderLangList(b);this.definition.minWidth=this.getSize().width;this.resize(this.definition.minWidth,
-this.definition.minHeight)}},onCancel:function(){n.reset()},onHide:function(){c.unlockSelection()},onShow:function(){c.fire("scaytDialogShown",this);if(0!=c.config.scayt_uiTabs[2]){var a=c.scayt,b=this.getContentElement("dictionaries","dictionaryName"),g=this.getContentElement("dictionaries","existDic").getElement().getParent(),e=this.getContentElement("dictionaries","notExistDic").getElement().getParent();g.hide();e.hide();null!=a.getUserDictionaryName()&&""!=a.getUserDictionaryName()?(this.getContentElement("dictionaries",
-"dictionaryName").setValue(a.getUserDictionaryName()),g.show()):(b.setValue(""),e.show())}},onOk:function(){var a=p,b=c.scayt;this.getContentElement("options","scaytOptions");a=a.getChangedOption.call(this);b.commitOption({changedOptions:a})},toggleDictionaryButtons:function(a){var b=this.getContentElement("dictionaries","existDic").getElement().getParent(),c=this.getContentElement("dictionaries","notExistDic").getElement().getParent();a?(b.show(),c.hide()):(b.hide(),c.show())},getChangedOption:function(){var a=
-{};if(1==c.config.scayt_uiTabs[0])for(var b=this.getContentElement("options","scaytOptions").getChild(),g=0;g<b.length;g++)b[g].isChanged()&&(a[b[g].id]=b[g].getValue());n.isChanged()&&(a[n.id]=c.config.scayt_sLang=n.currentLang=n.newLang);return a},buildRadioInputs:function(a,b,g){var e=new CKEDITOR.dom.element("div"),d="scaytLang_"+c.name+"_"+b,f=CKEDITOR.dom.element.createFromHtml('\x3cinput id\x3d"'+d+'" type\x3d"radio"  value\x3d"'+b+'" name\x3d"scayt_lang" /\x3e'),m=new CKEDITOR.dom.element("label"),
-k=c.scayt;e.setStyles({"white-space":"normal",position:"relative","padding-bottom":"2px"});f.on("click",function(a){n.newLang=a.sender.getValue()});m.appendText(a);m.setAttribute("for",d);g&&c.config.grayt_autoStartup&&m.setStyles({color:"#02b620"});e.append(f);e.append(m);b===k.getLang()&&(f.setAttribute("checked",!0),f.setAttribute("defaultChecked","defaultChecked"));return e},renderLangList:function(a){var b=a.find("#left-col-"+c.name).getItem(0);a=a.find("#right-col-"+c.name).getItem(0);var g=
-f.getScaytLangList(),e=f.getGraytLangList(),d={},l=[],m=0,k=!1,h;for(h in g.ltr)d[h]=g.ltr[h];for(h in g.rtl)d[h]=g.rtl[h];for(h in d)l.push([h,d[h]]);l.sort(function(a,b){var c=0;a[1]>b[1]?c=1:a[1]<b[1]&&(c=-1);return c});d={};for(k=0;k<l.length;k++)d[l[k][0]]=l[k][1];l=Math.round(l.length/2);for(h in d)m++,k=h in e.ltr||h in e.rtl,this.buildRadioInputs(d[h],h,k).appendTo(m<=l?b:a)},getLangBoxes:function(){return this.getContentElement("langs","langBox").getElement()},contents:function(a,b){var c=
-[],e=b.config.scayt_uiTabs;if(e){for(var d in e)1==e[d]&&c.push(a[d]);c.push(a[a.length-1])}else return a;return c}(q,c)};return p});
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+CKEDITOR.dialog.add( 'scaytDialog', function( editor ) {
+	var scayt_instance =  editor.scayt;
+
+	var aboutTabDefinition = '<p><img src="' + scayt_instance.getLogo() + '" /></p>' +
+				'<p>' + scayt_instance.getLocal('version') + scayt_instance.getVersion() + '</p>' +
+				'<p>' + scayt_instance.getLocal('text_copyrights') + '</p>';
+
+	var doc = CKEDITOR.document;
+
+	var optionGenerator = function() {
+		var scayt_instance_ = editor.scayt,
+			applicationConfig = scayt_instance.getApplicationConfig(),
+			optionArrayUiCheckboxes = [],
+			optionLocalizationList = {
+				"ignore-all-caps-words" 		: "label_allCaps",
+				"ignore-domain-names" 			: "label_ignoreDomainNames",
+				"ignore-words-with-mixed-cases" : "label_mixedCase",
+				"ignore-words-with-numbers" 	: "label_mixedWithDigits"
+			};
+
+		for(var option in applicationConfig) {
+
+			var checkboxConfig = {
+				type: "checkbox"
+			};
+
+			checkboxConfig.id  = option;
+			checkboxConfig.label  = scayt_instance.getLocal(optionLocalizationList[option]);
+
+			optionArrayUiCheckboxes.push(checkboxConfig);
+		}
+
+		return optionArrayUiCheckboxes;
+	};
+
+	var languageModelState = {
+		isChanged : function() {
+			return (this.newLang === null || this.currentLang === this.newLang) ? false : true;
+		},
+		currentLang: scayt_instance.getLang(),
+		newLang: null,
+		reset: function() {
+			this.currentLang = scayt_instance.getLang();
+			this.newLang = null;
+		},
+		id: 'lang'
+	};
+
+	var generateDialogTabs = function(tabsList, editor) {
+		var tabs = [],
+			uiTabs = editor.config.scayt_uiTabs;
+
+		if(!uiTabs) {
+			return tabsList;
+		} else {
+			for(var i in uiTabs) {
+				(uiTabs[i] == 1) && tabs.push(tabsList[i]);
+			}
+
+			tabs.push(tabsList[tabsList.length - 1]);
+		}
+
+		return tabs;
+	};
+
+	var dialogTabs = [{
+		id : 'options',
+		label : scayt_instance.getLocal('tab_options'),
+		onShow: function() {
+			// console.log("tab show");
+		},
+		elements : [
+			{
+				type: 'vbox',
+				id: 'scaytOptions',
+				children: optionGenerator(),
+				onShow: function() {
+					var optionsTab = this.getChild(),
+						scayt_instance =  editor.scayt;
+					for(var i = 0; i < this.getChild().length; i++) {
+						this.getChild()[i].setValue(scayt_instance.getApplicationConfig()[this.getChild()[i].id]);
+					}
+
+				}
+			}
+
+		]
+	},
+	{
+		id : 'langs',
+		label : scayt_instance.getLocal('tab_languages'),
+		elements : [
+			{
+				id: "leftLangColumn",
+				type: 'vbox',
+				align: 'left',
+				widths: ['100'],
+				children: [
+					{
+						type: 'html',
+						id: 'langBox',
+						style: 'overflow: hidden; white-space: normal;margin-bottom:15px;',
+						html: '<div><div style="float:left;width:45%;margin-left:5px;" id="left-col-' + editor.name + '"></div><div style="float:left;width:45%;margin-left:15px;" id="right-col-' + editor.name + '"></div></div>',
+						onShow: function() {
+							var scayt_instance =  editor.scayt;
+							var lang = scayt_instance.getLang(),
+								prefix_id = "scaytLang_",
+								radio = doc.getById(prefix_id + editor.name + '_' + lang);
+
+							radio.$.checked = true;
+						}
+					},
+					{
+						type: 'html',
+						id: 'graytLanguagesHint',
+						html: '<div style="margin:5px auto; width:95%;white-space:normal;" id="' + editor.name + 'graytLanguagesHint"><span style="width:10px;height:10px;display: inline-block; background:#02b620;vertical-align:top;margin-top:2px;"></span> - This languages are supported by Grammar As You Type(GRAYT).</div>',
+						onShow: function() {
+							var graytLanguagesHint = doc.getById(editor.name + 'graytLanguagesHint');
+
+							if (!editor.config.grayt_autoStartup) {
+								graytLanguagesHint.$.style.display = 'none';
+							}
+						}
+					}
+				]
+			}
+		]
+	},
+	{
+		id : 'dictionaries',
+		label : scayt_instance.getLocal('tab_dictionaries'),
+		elements : [
+			{
+				type: 'vbox',
+				id: 'rightCol_col__left',
+				children: [
+					{
+						type: 'html',
+						id: 'dictionaryNote',
+						html: ''
+					},
+					{
+						type: 'text',
+						id: 'dictionaryName',
+						label: scayt_instance.getLocal('label_fieldNameDic') || 'Dictionary name',
+						onShow: function(data) {
+							var dialog = data.sender,
+								scayt_instance = editor.scayt;
+
+							// IE7 specific fix
+							setTimeout(function() {
+								// clear dictionaryNote field
+								dialog.getContentElement("dictionaries", "dictionaryNote").getElement().setText('');
+
+								// restore/clear dictionaryName field
+								if(scayt_instance.getUserDictionaryName() != null && scayt_instance.getUserDictionaryName() != '') {
+									dialog.getContentElement("dictionaries", "dictionaryName").setValue(scayt_instance.getUserDictionaryName());
+								}
+							}, 0);
+						}
+					},
+					{
+						type: 'hbox',
+						id: 'notExistDic',
+						align: 'left',
+						style: 'width:auto;',
+						widths: [ '50%', '50%' ],
+						children: [
+							{
+								type: 'button',
+								id: 'createDic',
+								label: scayt_instance.getLocal('btn_createDic'),
+								title: scayt_instance.getLocal('btn_createDic'),
+								onClick: function() {
+									var dialog = this.getDialog(),
+										self = dialogDefinition,
+										scayt_instance = editor.scayt,
+										name = dialog.getContentElement("dictionaries", "dictionaryName").getValue();
+
+									scayt_instance.createUserDictionary(name, function(response) {
+										if(!response.error) {
+											self.toggleDictionaryButtons.call(dialog, true);
+										}
+										response.dialog = dialog;
+										response.command = "create";
+										response.name = name;
+										editor.fire("scaytUserDictionaryAction", response);
+									}, function(error) {
+										error.dialog = dialog;
+										error.command = "create";
+										error.name = name;
+										editor.fire("scaytUserDictionaryActionError", error);
+									});
+								}
+							},
+							{
+								type: 'button',
+								id: 'restoreDic',
+								label: scayt_instance.getLocal('btn_restoreDic'),
+								title: scayt_instance.getLocal('btn_restoreDic'),
+								onClick: function() {
+									var dialog = this.getDialog(),
+										scayt_instance = editor.scayt,
+										self = dialogDefinition,
+										name = dialog.getContentElement("dictionaries", "dictionaryName").getValue();
+
+									scayt_instance.restoreUserDictionary(name, function(response) {
+										response.dialog = dialog;
+										if(!response.error) {
+											self.toggleDictionaryButtons.call(dialog, true);
+										}
+										response.command = "restore";
+										response.name = name;
+										editor.fire("scaytUserDictionaryAction", response);
+									}, function(error) {
+										error.dialog = dialog;
+										error.command = "restore";
+										error.name = name;
+										editor.fire("scaytUserDictionaryActionError", error);
+									});
+								}
+							}
+						]
+					},
+					{
+						type: 'hbox',
+						id: 'existDic',
+						align: 'left',
+						style: 'width:auto;',
+						widths: [ '50%', '50%' ],
+						children: [
+							{
+								type: 'button',
+								id: 'removeDic',
+								label: scayt_instance.getLocal('btn_deleteDic'),
+								title: scayt_instance.getLocal('btn_deleteDic'),
+								onClick: function() {
+									var dialog = this.getDialog(),
+										scayt_instance = editor.scayt,
+										self = dialogDefinition,
+										dictionaryNameField = dialog.getContentElement("dictionaries", "dictionaryName"),
+										name = dictionaryNameField.getValue();
+
+									scayt_instance.removeUserDictionary(name, function(response) {
+										dictionaryNameField.setValue("");
+										if(!response.error) {
+											self.toggleDictionaryButtons.call(dialog, false);
+										}
+										response.dialog = dialog;
+										response.command = "remove";
+										response.name = name;
+										editor.fire("scaytUserDictionaryAction", response);
+									}, function(error) {
+										error.dialog = dialog;
+										error.command = "remove";
+										error.name = name;
+										editor.fire("scaytUserDictionaryActionError", error);
+									});
+								}
+							},
+							{
+								type: 'button',
+								id: 'renameDic',
+								label: scayt_instance.getLocal('btn_renameDic'),
+								title: scayt_instance.getLocal('btn_renameDic'),
+								onClick: function() {
+									var dialog = this.getDialog(),
+										scayt_instance = editor.scayt,
+										name = dialog.getContentElement("dictionaries", "dictionaryName").getValue();
+
+									scayt_instance.renameUserDictionary(name, function(response) {
+										response.dialog = dialog;
+										response.command = "rename";
+										response.name = name;
+										editor.fire("scaytUserDictionaryAction", response);
+									}, function(error) {
+										error.dialog = dialog;
+										error.command = "rename";
+										error.name = name;
+										editor.fire("scaytUserDictionaryActionError", error);
+									});
+								}
+							}
+						]
+					},
+					{
+						type: 'html',
+						id: 'dicInfo',
+						html: '<div id="dic_info_editor1" style="margin:5px auto; width:95%;white-space:normal;">' + scayt_instance.getLocal('text_descriptionDic')  + '</div>'
+					}
+				]
+			}
+		]
+	},
+	{
+		id : 'about',
+		label : scayt_instance.getLocal('tab_about'),
+		elements : [
+			{
+				type : 'html',
+				id : 'about',
+				style : 'margin: 5px 5px;',
+				html : '<div><div id="scayt_about_">' +
+						aboutTabDefinition +
+						'</div></div>'
+			}
+		]
+	}];
+
+	editor.on("scaytUserDictionaryAction", function(event) {
+		var UILib = SCAYT.prototype.UILib,
+			dialog = event.data.dialog,
+			dictionaryNote = dialog.getContentElement("dictionaries", "dictionaryNote").getElement(),
+			scayt_instance =  event.editor.scayt,
+			messageTemplate;
+
+		if(event.data.error === undefined) {
+
+			// success message
+			messageTemplate = scayt_instance.getLocal("message_success_" + event.data.command + "Dic");
+			messageTemplate = messageTemplate.replace('%s', event.data.name);
+			dictionaryNote.setText(messageTemplate);
+			UILib.css(dictionaryNote.$, {color: 'blue'});
+		} else {
+
+			// error message
+			if(event.data.name === '') {
+
+				// empty dictionary name
+				dictionaryNote.setText(scayt_instance.getLocal('message_info_emptyDic'));
+			} else {
+				messageTemplate = scayt_instance.getLocal("message_error_" + event.data.command + "Dic");
+				messageTemplate = messageTemplate.replace('%s', event.data.name);
+				dictionaryNote.setText(messageTemplate);
+			}
+			UILib.css(dictionaryNote.$, {color: 'red'});
+
+			if(scayt_instance.getUserDictionaryName() != null && scayt_instance.getUserDictionaryName() != '') {
+				dialog.getContentElement("dictionaries", "dictionaryName").setValue(scayt_instance.getUserDictionaryName());
+			} else {
+				dialog.getContentElement("dictionaries", "dictionaryName").setValue("");
+			}
+		}
+	});
+
+	editor.on("scaytUserDictionaryActionError", function(event) {
+		var UILib = SCAYT.prototype.UILib,
+			dialog = event.data.dialog,
+			dictionaryNote = dialog.getContentElement("dictionaries", "dictionaryNote").getElement(),
+			scayt_instance =  event.editor.scayt,
+			messageTemplate;
+
+		if(event.data.name === '') {
+
+			// empty dictionary name
+			dictionaryNote.setText(scayt_instance.getLocal('message_info_emptyDic'));
+		} else {
+			messageTemplate = scayt_instance.getLocal("message_error_" + event.data.command + "Dic");
+			messageTemplate = messageTemplate.replace('%s', event.data.name);
+			dictionaryNote.setText(messageTemplate);
+		}
+		UILib.css(dictionaryNote.$, {color: 'red'});
+
+
+		if(scayt_instance.getUserDictionaryName() != null && scayt_instance.getUserDictionaryName() != '') {
+			dialog.getContentElement("dictionaries", "dictionaryName").setValue(scayt_instance.getUserDictionaryName());
+		} else {
+			dialog.getContentElement("dictionaries", "dictionaryName").setValue("");
+		}
+
+	});
+
+	var plugin = CKEDITOR.plugins.scayt;
+
+	var dialogDefinition = {
+		title:          scayt_instance.getLocal('text_title'),
+		resizable:      CKEDITOR.DIALOG_RESIZE_BOTH,
+		minWidth: 		340,
+		minHeight: 		260,
+		onLoad: function() {
+			if(editor.config.scayt_uiTabs[1] == 0) {
+				return;
+			}
+
+			var dialog = this,
+				self = dialogDefinition,
+				langBoxes = self.getLangBoxes.call(dialog);
+
+			langBoxes.getParent().setStyle("white-space", "normal");
+
+			//dialog.data = editor.fire( 'scaytDialog', {} );
+			self.renderLangList(langBoxes);
+
+			var scayt_instance = editor.scayt;
+
+			this.definition.minWidth = this.getSize().width;
+			this.resize(this.definition.minWidth, this.definition.minHeight);
+		},
+		onCancel: function() {
+			languageModelState.reset();
+		},
+		onHide: function() {
+			editor.unlockSelection();
+		},
+		onShow: function() {
+			editor.fire("scaytDialogShown", this);
+
+			if(editor.config.scayt_uiTabs[2] == 0) {
+				return;
+			}
+
+			var scayt_instance = editor.scayt,
+				self = dialogDefinition,
+				dialog = this,
+				dictionaryNameField = dialog.getContentElement("dictionaries", "dictionaryName"),
+				existance = dialog.getContentElement("dictionaries", "existDic").getElement().getParent(),
+				notExistance = dialog.getContentElement("dictionaries", "notExistDic").getElement().getParent();
+
+			existance.hide();
+			notExistance.hide();
+
+			if(scayt_instance.getUserDictionaryName() != null && scayt_instance.getUserDictionaryName() != '') {
+				dialog.getContentElement("dictionaries", "dictionaryName").setValue(scayt_instance.getUserDictionaryName());
+				existance.show();
+			} else {
+				dictionaryNameField.setValue("");
+				notExistance.show();
+			}
+		},
+		onOk: function() {
+			var dialog = this,
+				self = dialogDefinition,
+				scayt_instance =  editor.scayt,
+				scaytOptions = dialog.getContentElement("options", "scaytOptions"),
+				changedOptions = self.getChangedOption.call(dialog);
+
+			scayt_instance.commitOption({ changedOptions: changedOptions });
+		},
+		toggleDictionaryButtons: function(exist) {
+			var existance = this.getContentElement("dictionaries", "existDic").getElement().getParent(),
+				notExistance = this.getContentElement("dictionaries", "notExistDic").getElement().getParent();
+
+			if(exist) {
+				existance.show();
+				notExistance.hide();
+			} else {
+				existance.hide();
+				notExistance.show();
+			}
+
+		},
+		getChangedOption: function() {
+			var changedOption = {};
+
+			if(editor.config.scayt_uiTabs[0] == 1) {
+				var dialog = this,
+					scaytOptions = dialog.getContentElement("options", "scaytOptions").getChild();
+
+				for(var i = 0; i < scaytOptions.length; i++) {
+					if(scaytOptions[i].isChanged()) {
+						changedOption[scaytOptions[i].id] = scaytOptions[i].getValue();
+					}
+				}
+			}
+
+			if(languageModelState.isChanged()) {
+				changedOption[languageModelState.id] = editor.config.scayt_sLang = languageModelState.currentLang = languageModelState.newLang;
+			}
+
+			return changedOption;
+		},
+		buildRadioInputs: function(key, value, isSupportedByGrayt) {
+			var divContainer = new CKEDITOR.dom.element( 'div' ),
+				doc = CKEDITOR.document,
+				id = "scaytLang_" + editor.name + '_' + value,
+				radio = CKEDITOR.dom.element.createFromHtml( '<input id="' +
+					id + '" type="radio" ' +
+					' value="' + value + '" name="scayt_lang" />' ),
+
+				radioLabel = new CKEDITOR.dom.element( 'label' ),
+				scayt_instance = editor.scayt;
+
+			divContainer.setStyles({
+				"white-space": "normal",
+				'position': 'relative',
+				'padding-bottom': '2px'
+			});
+
+			radio.on( 'click', function(data) {
+				languageModelState.newLang = data.sender.getValue();
+			});
+
+			radioLabel.appendText(key);
+			radioLabel.setAttribute("for", id);
+
+			if(isSupportedByGrayt && editor.config.grayt_autoStartup) {
+				radioLabel.setStyles({
+					'color': '#02b620'
+				});
+			}
+
+			divContainer.append(radio);
+			divContainer.append(radioLabel);
+
+			if(value === scayt_instance.getLang()) {
+				radio.setAttribute("checked", true);
+				radio.setAttribute('defaultChecked', 'defaultChecked');
+			}
+
+			return divContainer;
+		},
+		renderLangList: function(langBoxes) {
+			var dialog = this,
+				leftCol = langBoxes.find('#left-col-' + editor.name).getItem(0),
+				rightCol = langBoxes.find('#right-col-' + editor.name).getItem(0),
+				scaytLangList = scayt_instance.getScaytLangList(),
+				graytLangList = scayt_instance.getGraytLangList(),
+				mergedLangList = {},
+				sortable = [],
+				counter = 0,
+				isSupportedByGrayt = false,
+				half, lang;
+
+			for(lang in scaytLangList.ltr) {
+				mergedLangList[lang] = scaytLangList.ltr[lang];
+			}
+
+			for(lang in scaytLangList.rtl) {
+				mergedLangList[lang] = scaytLangList.rtl[lang];
+			}
+
+			// sort alphabetically lang list
+			for(lang in mergedLangList) {
+				sortable.push([lang, mergedLangList[lang]]);
+			}
+			sortable.sort(function(a, b) {
+				var result = 0;
+				if(a[1] > b[1]) {
+					result = 1;
+				} else if(a[1] < b[1]) {
+					result = -1;
+				}
+				return result;
+			});
+			mergedLangList = {};
+			for(var i = 0; i < sortable.length; i++) {
+				mergedLangList[sortable[i][0]] = sortable[i][1];
+			}
+
+			half = Math.round(sortable.length / 2);
+
+			for(lang in mergedLangList) {
+				counter++;
+				isSupportedByGrayt = (lang in graytLangList.ltr) || (lang in graytLangList.rtl);
+				dialog.buildRadioInputs(mergedLangList[lang], lang, isSupportedByGrayt).appendTo(counter <= half ? leftCol : rightCol);
+			}
+		},
+		getLangBoxes: function() {
+			var dialog = this,
+				langboxes = dialog.getContentElement("langs", "langBox").getElement();
+
+			return langboxes;
+		},
+		contents: generateDialogTabs(dialogTabs, editor)
+	};
+
+	return dialogDefinition;
+});

+ 71 - 71
app/Resources/public/assets/ckeditor/plugins/scayt/dialogs/toolbar.css

@@ -1,71 +1,71 @@
-a
-{
-	text-decoration:none;
-	padding: 2px 4px 4px 6px;
-	display : block;
-	border-width: 1px;
-	border-style: solid;
-	margin : 0px;
-}
-
-a.cke_scayt_toogle:hover,
-a.cke_scayt_toogle:focus,
-a.cke_scayt_toogle:active
-{
-	border-color: #316ac5;
-	background-color: #dff1ff;
-	color : #000;
-	cursor: pointer;
-	margin : 0px;
-}
-a.cke_scayt_toogle {
-	color : #316ac5;
-	border-color: #fff;
-}
-.scayt_enabled a.cke_scayt_item {
-	color : #316ac5;
-	border-color: #fff;
-	margin : 0px;
-}
-.scayt_disabled a.cke_scayt_item {
-	color : gray;
-	border-color : #fff;
-}
-.scayt_enabled a.cke_scayt_item:hover,
-.scayt_enabled a.cke_scayt_item:focus,
-.scayt_enabled a.cke_scayt_item:active
-{
-	border-color: #316ac5;
-	background-color: #dff1ff;
-	color : #000;
-	cursor: pointer;
-}
-.scayt_disabled a.cke_scayt_item:hover,
-.scayt_disabled a.cke_scayt_item:focus,
-.scayt_disabled a.cke_scayt_item:active
-{
-	border-color: gray;
-	background-color: #dff1ff;
-	color : gray;
-	cursor: no-drop;
-}
-.cke_scayt_set_on, .cke_scayt_set_off
-{
-	display: none;
-}
-.scayt_enabled .cke_scayt_set_on
-{
-	display: none;
-}
-.scayt_disabled .cke_scayt_set_on
-{
-	display: inline;
-}
-.scayt_disabled .cke_scayt_set_off
-{
-	display: none;
-}
-.scayt_enabled  .cke_scayt_set_off
-{
-	display: inline;
-}
+a
+{
+	text-decoration:none;
+	padding: 2px 4px 4px 6px;
+	display : block;
+	border-width: 1px;
+	border-style: solid;
+	margin : 0px;
+}
+
+a.cke_scayt_toogle:hover,
+a.cke_scayt_toogle:focus,
+a.cke_scayt_toogle:active
+{
+	border-color: #316ac5;
+	background-color: #dff1ff;
+	color : #000;
+	cursor: pointer;
+	margin : 0px;
+}
+a.cke_scayt_toogle {
+	color : #316ac5;
+	border-color: #fff;
+}
+.scayt_enabled a.cke_scayt_item {
+	color : #316ac5;
+	border-color: #fff;
+	margin : 0px;
+}
+.scayt_disabled a.cke_scayt_item {
+	color : gray;
+	border-color : #fff;
+}
+.scayt_enabled a.cke_scayt_item:hover,
+.scayt_enabled a.cke_scayt_item:focus,
+.scayt_enabled a.cke_scayt_item:active
+{
+	border-color: #316ac5;
+	background-color: #dff1ff;
+	color : #000;
+	cursor: pointer;
+}
+.scayt_disabled a.cke_scayt_item:hover,
+.scayt_disabled a.cke_scayt_item:focus,
+.scayt_disabled a.cke_scayt_item:active
+{
+	border-color: gray;
+	background-color: #dff1ff;
+	color : gray;
+	cursor: no-drop;
+}
+.cke_scayt_set_on, .cke_scayt_set_off
+{
+	display: none;
+}
+.scayt_enabled .cke_scayt_set_on
+{
+	display: none;
+}
+.scayt_disabled .cke_scayt_set_on
+{
+	display: inline;
+}
+.scayt_disabled .cke_scayt_set_off
+{
+	display: none;
+}
+.scayt_enabled  .cke_scayt_set_off
+{
+	display: inline;
+}

BIN
app/Resources/public/assets/ckeditor/plugins/scayt/icons/hidpi/scayt.png


BIN
app/Resources/public/assets/ckeditor/plugins/scayt/icons/scayt.png


+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/af.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'af', {
+	btn_about: 'SCAYT info',
+	btn_dictionaries: 'Woordeboeke',
+	btn_disable: 'SCAYT af',
+	btn_enable: 'SCAYT aan',
+	btn_langs:'Tale',
+	btn_options: 'Opsies',
+	text_title:  'Speltoets terwyl u tik'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/ar.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'ar', {
+	btn_about: 'عن SCAYT',
+	btn_dictionaries: 'قواميس',
+	btn_disable: 'تعطيل SCAYT',
+	btn_enable: 'تفعيل SCAYT',
+	btn_langs:'لغات',
+	btn_options: 'خيارات',
+	text_title:  'تدقيق إملائي أثناء الكتابة'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/bg.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'bg', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Речници',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Languages',
+	btn_options: 'Options',
+	text_title:  'Spell Check As You Type'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/bn.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'bn', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Dictionaries',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Languages',
+	btn_options: 'Options',
+	text_title:  'Spell Check As You Type'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/bs.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'bs', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Dictionaries',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Languages',
+	btn_options: 'Options',
+	text_title:  'Spell Check As You Type'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/ca.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'ca', {
+	btn_about: 'Quant a l\'SCAYT',
+	btn_dictionaries: 'Diccionaris',
+	btn_disable: 'Deshabilita SCAYT',
+	btn_enable: 'Habilitat l\'SCAYT',
+	btn_langs:'Idiomes',
+	btn_options: 'Opcions',
+	text_title:  'Spell Check As You Type'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/cs.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'cs', {
+	btn_about: 'O aplikaci SCAYT',
+	btn_dictionaries: 'Slovníky',
+	btn_disable: 'Vypnout SCAYT',
+	btn_enable: 'Zapnout SCAYT',
+	btn_langs:'Jazyky',
+	btn_options: 'Nastavení',
+	text_title:  'Kontrola pravopisu během psaní (SCAYT)'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/cy.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'cy', {
+	btn_about: 'Ynghylch SCAYT',
+	btn_dictionaries: 'Geiriaduron',
+	btn_disable: 'Analluogi SCAYT',
+	btn_enable: 'Galluogi SCAYT',
+	btn_langs:'Ieithoedd',
+	btn_options: 'Opsiynau',
+	text_title:  'Gwirio\'r Sillafu Wrth Deipio'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/da.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'da', {
+	btn_about: 'Om SCAYT',
+	btn_dictionaries: 'Ordbøger',
+	btn_disable: 'Deaktivér SCAYT',
+	btn_enable: 'Aktivér SCAYT',
+	btn_langs:'Sprog',
+	btn_options: 'Indstillinger',
+	text_title: 'Stavekontrol mens du skriver'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/de.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'de', {
+	btn_about: 'Über SCAYT',
+	btn_dictionaries: 'Wörterbücher',
+	btn_disable: 'SCAYT ausschalten',
+	btn_enable: 'SCAYT einschalten',
+	btn_langs:'Sprachen',
+	btn_options: 'Optionen',
+	text_title: 'Rechtschreibprüfung während der Texteingabe (SCAYT)'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/el.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'el', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Λεξικά',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Γλώσσες',
+	btn_options: 'Επιλογές',
+	text_title: 'Spell Check As You Type'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/en-au.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'en-au', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Dictionaries',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Languages',
+	btn_options: 'Options',
+	text_title: 'Spell Check As You Type'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/en-ca.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'en-ca', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Dictionaries',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Languages',
+	btn_options: 'Options',
+	text_title: 'Spell Check As You Type'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/en-gb.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'en-gb', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Dictionaries',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Languages',
+	btn_options: 'Options',
+	text_title: 'Spell Check As You Type'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/en.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'en', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Dictionaries',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Languages',
+	btn_options: 'Options',
+	text_title: 'Spell Check As You Type'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/eo.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'eo', {
+	btn_about: 'Pri OKDVT',
+	btn_dictionaries: 'Vortaroj',
+	btn_disable: 'Malebligi OKDVT',
+	btn_enable: 'Ebligi OKDVT',
+	btn_langs:'Lingvoj',
+	btn_options: 'Opcioj',
+	text_title:  'OrtografiKontrolado Dum Vi Tajpas (OKDVT)'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/es.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'es', {
+	btn_about: 'Acerca de Corrector',
+	btn_dictionaries: 'Diccionarios',
+	btn_disable: 'Desactivar Corrector',
+	btn_enable: 'Activar Corrector',
+	btn_langs:'Idiomas',
+	btn_options: 'Opciones',
+	text_title: 'Comprobar Ortografía Mientras Escribe'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/et.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'et', {
+	btn_about: 'SCAYT-ist lähemalt',
+	btn_dictionaries: 'Sõnaraamatud',
+	btn_disable: 'SCAYT keelatud',
+	btn_enable: 'SCAYT lubatud',
+	btn_langs:'Keeled',
+	btn_options: 'Valikud',
+	text_title:  'Õigekirjakontroll kirjutamise ajal'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/eu.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'eu', {
+	btn_about: 'SCAYTi buruz',
+	btn_dictionaries: 'Hiztegiak',
+	btn_disable: 'Desgaitu SCAYT',
+	btn_enable: 'Gaitu SCAYT',
+	btn_langs:'Hizkuntzak',
+	btn_options: 'Aukerak',
+	text_title:  'Ortografia Zuzenketa Idatzi Ahala (SCAYT)'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/fa.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'fa', {
+	btn_about: 'درباره SCAYT',
+	btn_dictionaries: 'دیکشنریها',
+	btn_disable: 'غیرفعالسازی SCAYT',
+	btn_enable: 'فعالسازی SCAYT',
+	btn_langs:'زبانها',
+	btn_options: 'گزینهها',
+	text_title:  'بررسی املای تایپ شما'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/fi.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'fi', {
+	btn_about: 'Tietoja oikoluvusta kirjoitetaessa',
+	btn_dictionaries: 'Sanakirjat',
+	btn_disable: 'Poista käytöstä oikoluku kirjoitetaessa',
+	btn_enable: 'Ota käyttöön oikoluku kirjoitettaessa',
+	btn_langs:'Kielet',
+	btn_options: 'Asetukset',
+	text_title: 'Oikolue kirjoitettaessa'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/fo.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'fo', {
+	btn_about: 'Um SCAYT',
+	btn_dictionaries: 'Orðabøkur',
+	btn_disable: 'Nokta SCAYT',
+	btn_enable: 'Loyv SCAYT',
+	btn_langs:'Tungumál',
+	btn_options: 'Uppseting',
+	text_title:  'Kanna stavseting, meðan tú skrivar'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/fr-ca.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'fr-ca', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Dictionaries',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Languages',
+	btn_options: 'Options',
+	text_title:  'Spell Check As You Type'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/fr.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'fr', {
+	btn_about: 'A propos de SCAYT',
+	btn_dictionaries: 'Dictionnaires',
+	btn_disable: 'Désactiver SCAYT',
+	btn_enable: 'Activer SCAYT',
+	btn_langs:'Langues',
+	btn_options: 'Options',
+	text_title: 'Vérification de l\'Orthographe en Cours de Frappe (SCAYT)'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/gl.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'gl', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Dictionaries',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Languages',
+	btn_options: 'Options',
+	text_title:  'Spell Check As You Type'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/gu.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'gu', {
+	btn_about: 'SCAYT વિષે',
+	btn_dictionaries: 'શબ્દકોશ',
+	btn_disable: 'SCAYT ડિસેબલ કરવું',
+	btn_enable: 'SCAYT એનેબલ કરવું',
+	btn_langs:'ભાષાઓ',
+	btn_options: 'વિકલ્પો',
+	text_title:  'ટાઈપ કરતા સ્પેલ તપાસો'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/he.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'he', {
+	btn_about: 'אודות SCAYT',
+	btn_dictionaries: 'מילון',
+	btn_disable: 'בטל SCAYT',
+	btn_enable: 'אפשר SCAYT',
+	btn_langs:'שפות',
+	btn_options: 'אפשרויות',
+	text_title:  'בדיקת איות בזמן כתיבה (SCAYT)'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/hi.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'hi', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Dictionaries',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Languages',
+	btn_options: 'Options',
+	text_title:  'Spell Check As You Type'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/hr.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'hr', {
+	btn_about: 'O SCAYT',
+	btn_dictionaries: 'Rječnici',
+	btn_disable: 'Onemogući SCAYT',
+	btn_enable: 'Omogući SCAYT',
+	btn_langs:'Jezici',
+	btn_options: 'Opcije',
+	text_title:  'Provjeri pravopis tijekom tipkanja (SCAYT)'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/hu.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'hu', {
+	btn_about: 'SCAYT névjegy',
+	btn_dictionaries: 'Szótár',
+	btn_disable: 'SCAYT letiltása',
+	btn_enable: 'SCAYT engedélyezése',
+	btn_langs:'Nyelvek',
+	btn_options: 'Beállítások',
+	text_title:  'Helyesírás ellenőrzés gépelés közben'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/is.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'is', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Dictionaries',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Languages',
+	btn_options: 'Options',
+	text_title:  'Spell Check As You Type'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/it.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'it', {
+	btn_about: 'About COMS',
+	btn_dictionaries: 'Dizionari',
+	btn_disable: 'Disabilita COMS',
+	btn_enable: 'Abilita COMS',
+	btn_langs:'Lingue',
+	btn_options: 'Opzioni',
+	text_title: 'Controllo Ortografico Mentre Scrivi'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/ja.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'ja', {
+	btn_about: 'SCAYTバージョン',
+	btn_dictionaries: '辞書',
+	btn_disable: 'SCAYT無効',
+	btn_enable: 'SCAYT有効',
+	btn_langs:'言語',
+	btn_options: 'オプション',
+	text_title:  'スペルチェック設定(SCAYT)'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/ka.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'ka', {
+	btn_about: 'SCAYT-ის შესახებ',
+	btn_dictionaries: 'ლექსიკონები',
+	btn_disable: 'SCAYT-ის გამორთვა',
+	btn_enable: 'SCAYT-ის ჩართვა',
+	btn_langs:'ენები',
+	btn_options: 'პარამეტრები',
+	text_title:  'მართლწერის შემოწმება კრეფისას'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/km.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'km', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Dictionaries',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Languages',
+	btn_options: 'Options',
+	text_title:  'Spell Check As You Type'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/ko.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'ko', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Dictionaries',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Languages',
+	btn_options: 'Options',
+	text_title:  'Spell Check As You Type'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/ku.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'ku', {
+	btn_about: 'دهربارهی SCAYT',
+	btn_dictionaries: 'فهرههنگهکان',
+	btn_disable: 'ناچالاککردنی SCAYT',
+	btn_enable: 'چالاککردنی SCAYT',
+	btn_langs:'زمانهکان',
+	btn_options: 'ههڵبژارده',
+	text_title:  'پشکنینی نووسه لهکاتی نووسین'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/lt.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'lt', {
+	btn_about: 'Apie SCAYT',
+	btn_dictionaries: 'Žodynai',
+	btn_disable: 'Išjungti SCAYT',
+	btn_enable: 'Įjungti SCAYT',
+	btn_langs:'Kalbos',
+	btn_options: 'Parametrai',
+	text_title:  'Tikrinti klaidas kai rašoma'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/lv.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'lv', {
+	btn_about: 'Par SCAYT',
+	btn_dictionaries: 'Vārdnīcas',
+	btn_disable: 'Atslēgt SCAYT',
+	btn_enable: 'Ieslēgt SCAYT',
+	btn_langs:'Valodas',
+	btn_options: 'Uzstādījumi',
+	text_title:  'Pārbaudīt gramatiku rakstot'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/mk.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'mk', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Dictionaries',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Languages',
+	btn_options: 'Options',
+	text_title:  'Spell Check As You Type'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/mn.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'mn', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Толь бичгүүд',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Хэлүүд',
+	btn_options: 'Сонголт',
+	text_title:  'Spell Check As You Type'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/ms.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'ms', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Dictionaries',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Languages',
+	btn_options: 'Options',
+	text_title:  'Spell Check As You Type' // MISSING
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/nb.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'nb', {
+	btn_about: 'Om SCAYT',
+	btn_dictionaries: 'Ordbøker',
+	btn_disable: 'Slå av SCAYT',
+	btn_enable: 'Slå på SCAYT',
+	btn_langs:'Språk',
+	btn_options: 'Valg',
+	text_title:  'Stavekontroll mens du skriver'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/nl.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'nl', {
+	btn_about: 'Over SCAYT',
+	btn_dictionaries: 'Woordenboeken',
+	btn_disable: 'SCAYT uitschakelen',
+	btn_enable: 'SCAYT inschakelen',
+	btn_langs:'Talen',
+	btn_options: 'Opties',
+	text_title: 'Controleer de spelling tijdens het typen'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/no.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'no', {
+	btn_about: 'Om SCAYT',
+	btn_dictionaries: 'Ordbøker',
+	btn_disable: 'Slå av SCAYT',
+	btn_enable: 'Slå på SCAYT',
+	btn_langs:'Språk',
+	btn_options: 'Valg',
+	text_title: 'Stavekontroll mens du skriver'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/pl.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'pl', {
+	btn_about: 'Informacje o SCAYT',
+	btn_dictionaries: 'Słowniki',
+	btn_disable: 'Wyłącz SCAYT',
+	btn_enable: 'Włącz SCAYT',
+	btn_langs:'Języki',
+	btn_options: 'Opcje',
+	text_title:  'Sprawdź pisownię podczas pisania (SCAYT)'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/pt-br.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'pt-br', {
+	btn_about: 'Sobre a correção ortográfica durante a digitação',
+	btn_dictionaries: 'Dicionários',
+	btn_disable: 'Desabilitar correção ortográfica durante a digitação',
+	btn_enable: 'Habilitar correção ortográfica durante a digitação',
+	btn_langs:'Idiomas',
+	btn_options: 'Opções',
+	text_title: 'Correção ortográfica durante a digitação'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/pt.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'pt', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Dictionaries',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Languages',
+	btn_options: 'Options',
+	text_title: 'Spell Check As You Type' // MISSING
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/ro.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'ro', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Dictionaries',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Languages',
+	btn_options: 'Options',
+	text_title:  'Spell Check As You Type' // MISSING
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/ru.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'ru', {
+	btn_about: 'О SCAYT',
+	btn_dictionaries: 'Словари',
+	btn_disable: 'Отключить SCAYT',
+	btn_enable: 'Включить SCAYT',
+	btn_langs:'Языки',
+	btn_options: 'Настройки',
+	text_title: 'Проверка орфографии по мере ввода (SCAYT)'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/sk.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'sk', {
+	btn_about: 'O KPPP (Kontrola pravopisu počas písania)',
+	btn_dictionaries: 'Slovníky',
+	btn_disable: 'Zakázať  KPPP (Kontrola pravopisu počas písania)',
+	btn_enable: 'Povoliť KPPP (Kontrola pravopisu počas písania)',
+	btn_langs:'Jazyky',
+	btn_options: 'Možnosti',
+	text_title:  'Kontrola pravopisu počas písania'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/sl.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'sl', {
+	btn_about: 'O storitvi SCAYT',
+	btn_dictionaries: 'Slovarji',
+	btn_disable: 'Onemogoči SCAYT',
+	btn_enable: 'Omogoči SCAYT',
+	btn_langs:'Jeziki',
+	btn_options: 'Možnosti',
+	text_title:  'Črkovanje med tipkanjem'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/sr-latn.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'sr-latn', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Dictionaries',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Languages',
+	btn_options: 'Options',
+	text_title:  'Spell Check As You Type' // MISSING
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/sr.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'sr', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Dictionaries',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Languages',
+	btn_options: 'Options',
+	text_title:  'Spell Check As You Type' // MISSING
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/sv.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'sv', {
+	btn_about: 'Om SCAYT',
+	btn_dictionaries: 'Ordlistor',
+	btn_disable: 'Inaktivera SCAYT',
+	btn_enable: 'Aktivera SCAYT',
+	btn_langs:'Språk',
+	btn_options: 'Inställningar',
+	text_title: 'Stavningskontroll medan du skriver'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/th.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'th', {
+	btn_about: 'About SCAYT',
+	btn_dictionaries: 'Dictionaries',
+	btn_disable: 'Disable SCAYT',
+	btn_enable: 'Enable SCAYT',
+	btn_langs:'Languages',
+	btn_options: 'Options',
+	text_title:  'Spell Check As You Type' // MISSING
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/tr.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'tr', {
+	btn_about: 'SCAYT\'ı hakkında',
+	btn_dictionaries: 'Sözlükler',
+	btn_disable: 'SCAYT\'ı pasifleştir',
+	btn_enable: 'SCAYT\'ı etkinleştir',
+	btn_langs:'Diller',
+	btn_options: 'Seçenekler',
+	text_title:  'Girmiş olduğunuz kelime denetimi'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/ug.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'ug', {
+	btn_about: 'شۇئان ئىملا تەكشۈرۈش ھەققىدە',
+	btn_dictionaries: 'لۇغەت',
+	btn_disable: 'شۇئان ئىملا تەكشۈرۈشنى چەكلە',
+	btn_enable: 'شۇئان ئىملا تەكشۈرۈشنى قوزغات',
+	btn_langs:'تىل',
+	btn_options: 'تاللانما',
+	text_title:  'شۇئان ئىملا تەكشۈر'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/uk.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'uk', {
+	btn_about: 'Про SCAYT',
+	btn_dictionaries: 'Словники',
+	btn_disable: 'Вимкнути SCAYT',
+	btn_enable: 'Ввімкнути SCAYT',
+	btn_langs:'Мови',
+	btn_options: 'Опції',
+	text_title:  'Перефірка орфографії по мірі набору'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/vi.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'vi', {
+	btn_about: 'Thông tin về SCAYT',
+	btn_dictionaries: 'Từ điển',
+	btn_disable: 'Tắt SCAYT',
+	btn_enable: 'Bật SCAYT',
+	btn_langs:'Ngôn ngữ',
+	btn_options: 'Tùy chọn',
+	text_title:  'Kiểm tra chính tả ngay khi gõ chữ (SCAYT)'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/zh-cn.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'zh-cn', {
+	btn_about: '关于即时拼写检查',
+	btn_dictionaries: '字典',
+	btn_disable: '禁用即时拼写检查',
+	btn_enable: '启用即时拼写检查',
+	btn_langs:'语言',
+	btn_options: '选项',
+	text_title:  '即时拼写检查'
+});

+ 13 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/lang/zh.js

@@ -0,0 +1,13 @@
+/*
+Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'scayt', 'zh', {
+	btn_about: '關於即時拼寫檢查',
+	btn_dictionaries: '字典',
+	btn_disable: '關閉即時拼寫檢查',
+	btn_enable: '啟用即時拼寫檢查',
+	btn_langs: '語言',
+	btn_options: '選項',
+	text_title:  '即時拼寫檢查'
+});

+ 1877 - 0
app/Resources/public/assets/ckeditor/plugins/scayt/plugin.js

@@ -0,0 +1,1877 @@
+'use strict';
+CKEDITOR.plugins.add('scayt', {
+
+	//requires : ['menubutton', 'dialog'],
+	requires: 'menubutton,dialog',
+	lang: 'af,ar,bg,bn,bs,ca,cs,cy,da,de,el,en-au,en-ca,en-gb,en,eo,es,et,eu,fa,fi,fo,fr-ca,fr,gl,gu,he,hi,hr,hu,is,it,ja,ka,km,ko,lt,lv,mk,mn,ms,nb,nl,no,pl,pt-br,pt,ro,ru,sk,sl,sr-latn,sr,sv,th,tr,ug,uk,vi,zh-cn,zh', // %REMOVE_LINE_CORE%
+	icons: 'scayt', // %REMOVE_LINE_CORE%
+	hidpi: true, // %REMOVE_LINE_CORE%
+	tabToOpen : null,
+	dialogName: 'scaytDialog',
+	init: function(editor) {
+		var self = this,
+			plugin = CKEDITOR.plugins.scayt;
+
+		this.bindEvents(editor);
+		this.parseConfig(editor);
+		this.addRule(editor);
+
+		// source mode
+		CKEDITOR.dialog.add(this.dialogName, CKEDITOR.getUrl(this.path + 'dialogs/options.js'));
+		// end source mode
+
+		this.addMenuItems(editor);
+		var config = editor.config,
+			lang = editor.lang.scayt,
+			env = CKEDITOR.env;
+
+		editor.ui.add('Scayt', CKEDITOR.UI_MENUBUTTON, {
+			label : lang.text_title,
+			title : ( editor.plugins.wsc ? editor.lang.wsc.title : lang.text_title ),
+			// SCAYT doesn't work in IE Compatibility Mode and IE (8 & 9) Quirks Mode
+			modes : {wysiwyg: !(env.ie && ( env.version < 8 || env.quirks ) ) },
+			toolbar: 'spellchecker,20',
+			refresh: function() {
+				var buttonState = editor.ui.instances.Scayt.getState();
+
+				// check if scayt is created
+				if(editor.scayt) {
+					// check if scayt is enabled
+					if(plugin.state.scayt[editor.name]) {
+						buttonState = CKEDITOR.TRISTATE_ON;
+					} else {
+						buttonState = CKEDITOR.TRISTATE_OFF;
+					}
+				}
+
+				editor.fire('scaytButtonState', buttonState);
+			},
+			onRender: function() {
+				var that = this;
+
+				editor.on('scaytButtonState', function(ev) {
+					if(typeof ev.data !== undefined) {
+						that.setState(ev.data);
+					}
+				});
+			},
+			onMenu : function() {
+				var scaytInstance = editor.scayt;
+
+				editor.getMenuItem('scaytToggle').label = editor.lang.scayt[(scaytInstance ? plugin.state.scayt[editor.name] : false) ? 'btn_disable' : 'btn_enable'];
+
+				// If UI tab is disabled we shouldn't show menu item
+				var menuDefinition = {
+					scaytToggle  : CKEDITOR.TRISTATE_OFF,
+					scaytOptions : scaytInstance ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED,
+					scaytLangs   : scaytInstance ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED,
+					scaytDict    : scaytInstance ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED,
+					scaytAbout   : scaytInstance ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED,
+					WSC          : editor.plugins.wsc ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED
+				};
+
+				if(!editor.config.scayt_uiTabs[0]) {
+					delete menuDefinition.scaytOptions;
+				}
+
+				if(!editor.config.scayt_uiTabs[1]) {
+					delete menuDefinition.scaytLangs;
+				}
+
+				if(!editor.config.scayt_uiTabs[2]) {
+					delete menuDefinition.scaytDict;
+				}
+
+				return menuDefinition;
+			}
+		});
+
+		// If the 'contextmenu' plugin is loaded, register the listeners.
+		if(editor.contextMenu && editor.addMenuItems) {
+			editor.contextMenu.addListener(function(element, selection) {
+				var scaytInstance = editor.scayt,
+					result, selectionNode;
+
+				if(scaytInstance) {
+					selectionNode = scaytInstance.getSelectionNode();
+
+					// SCAYT shouldn't build context menu if instance isnot created or word is without misspelling or grammar problem
+					if(selectionNode) {
+						var items = self.menuGenerator(editor, selectionNode);
+
+						scaytInstance.showBanner('.' + editor.contextMenu._.definition.panel.className.split(' ').join(' .'));
+						result = items;
+					}
+				}
+
+				return result;
+			});
+
+			editor.contextMenu._.onHide = CKEDITOR.tools.override(editor.contextMenu._.onHide, function(org) {
+				return function() {
+					var scaytInstance = editor.scayt;
+
+					if(scaytInstance) {
+						scaytInstance.hideBanner();
+					}
+
+					return org.apply(this);
+				};
+			});
+		}
+	},
+	addMenuItems: function(editor) {
+		var self = this,
+			plugin = CKEDITOR.plugins.scayt,
+			graytGroups = ['grayt_description', 'grayt_suggest', 'grayt_control'],
+			menuGroup = 'scaytButton';
+
+		editor.addMenuGroup(menuGroup);
+
+		var items_order = editor.config.scayt_contextMenuItemsOrder.split('|');
+
+		for(var pos = 0 ; pos < items_order.length ; pos++) {
+			items_order[pos] = 'scayt_' + items_order[pos];
+		}
+		items_order = graytGroups.concat(items_order);
+
+		if(items_order && items_order.length) {
+			for(var pos = 0 ; pos < items_order.length ; pos++) {
+				editor.addMenuGroup(items_order[pos], pos - 10);
+			}
+		}
+
+		editor.addCommand( 'scaytToggle', {
+			exec: function(editor) {
+				var scaytInstance = editor.scayt;
+
+				plugin.state.scayt[editor.name] = !plugin.state.scayt[editor.name];
+
+				if(plugin.state.scayt[editor.name] === true) {
+					if(!scaytInstance) {
+						plugin.createScayt(editor);
+					}
+				} else {
+					if(scaytInstance) {
+						plugin.destroy(editor);
+					}
+				}
+			}
+		} );
+
+		editor.addCommand( 'scaytAbout', {
+			exec: function(editor) {
+				var scaytInstance = editor.scayt;
+
+				scaytInstance.tabToOpen = 'about';
+				editor.lockSelection();
+				editor.openDialog(self.dialogName);
+			}
+		} );
+
+		editor.addCommand( 'scaytOptions', {
+			exec: function(editor) {
+				var scaytInstance = editor.scayt;
+
+				scaytInstance.tabToOpen = 'options';
+				editor.lockSelection();
+				editor.openDialog(self.dialogName);
+			}
+		} );
+
+		editor.addCommand( 'scaytLangs', {
+			exec: function(editor) {
+				var scaytInstance = editor.scayt;
+
+				scaytInstance.tabToOpen = 'langs';
+				editor.lockSelection();
+				editor.openDialog(self.dialogName);
+			}
+		} );
+
+		editor.addCommand( 'scaytDict', {
+			exec: function(editor) {
+				var scaytInstance = editor.scayt;
+
+				scaytInstance.tabToOpen = 'dictionaries';
+				editor.lockSelection();
+				editor.openDialog(self.dialogName);
+			}
+		} );
+
+		var uiMenuItems = {
+			scaytToggle: {
+				label : editor.lang.scayt.btn_enable,
+				group : menuGroup,
+				command: 'scaytToggle'
+			},
+			scaytAbout: {
+				label : editor.lang.scayt.btn_about,
+				group : menuGroup,
+				command: 'scaytAbout'
+			},
+			scaytOptions: {
+				label : editor.lang.scayt.btn_options,
+				group : menuGroup,
+				command: 'scaytOptions'
+			},
+			scaytLangs: {
+				label : editor.lang.scayt.btn_langs,
+				group : menuGroup,
+				command: 'scaytLangs'
+			},
+			scaytDict: {
+				label : editor.lang.scayt.btn_dictionaries,
+				group : menuGroup,
+				command: 'scaytDict'
+			}
+		};
+
+		if(editor.plugins.wsc) {
+			uiMenuItems.WSC = {
+				label : editor.lang.wsc.toolbar,
+				group : menuGroup,
+				onClick: function() {
+					var inlineMode = (editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE),
+						plugin = CKEDITOR.plugins.scayt,
+						scaytInstance = editor.scayt,
+						text = inlineMode ? editor.container.getText() : editor.document.getBody().getText();
+
+					text = text.replace(/\s/g, '');
+
+					if(text) {
+						if(scaytInstance && plugin.state.scayt[editor.name] && scaytInstance.setMarkupPaused) {
+							scaytInstance.setMarkupPaused(true);
+						}
+
+						editor.lockSelection();
+						editor.execCommand('checkspell');
+					} else {
+						alert('Nothing to check!');
+					}
+				}
+			}
+		}
+
+		editor.addMenuItems(uiMenuItems);
+	},
+	bindEvents: function(editor) {
+		var self = this,
+			plugin = CKEDITOR.plugins.scayt,
+			inline_mode = (editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE);
+
+		var scaytDestroy = function() {
+			plugin.destroy(editor);
+		};
+
+		/*
+		 * Dirty fix for placeholder drag&drop
+		 * Should be fixed with next release
+		 */
+		/*
+		editor.on('drop', function(evt) {
+			var dropRange = evt.data.dropRange;
+			var b = dropRange.createBookmark(true);
+			editor.scayt.removeMarkupInSelectionNode({ selectionNode: evt.data.target.$, forceBookmark: false });
+			dropRange.moveToBookmark(b);
+
+			evt.data.dropRange = dropRange;
+			return evt;
+		}, this, null, 0); // We should be sure that we modify dropRange before CKEDITOR.plugins.clipboard calls
+		*/
+
+		var contentDomReady = function() {
+			// The event is fired when editable iframe node was reinited so we should restart our service
+			if (plugin.state.scayt[editor.name] && !editor.readOnly && !editor.scayt) {
+				plugin.createScayt(editor);
+			}
+		};
+
+		var addMarkupStateHandlers = function() {
+			var editable = editor.editable();
+
+			editable.attachListener( editable, 'focus', function( evt ) {
+				if( CKEDITOR.plugins.scayt && !editor.scayt ) {
+					setTimeout(contentDomReady, 0); // we need small timeout in order to correctly set initial 'focused' option value in SCAYT core
+				}
+
+				var pluginStatus = CKEDITOR.plugins.scayt && CKEDITOR.plugins.scayt.state.scayt[editor.name] && editor.scayt,
+					selectedElement, ranges, textLength, range;
+
+				if((inline_mode ? true : pluginStatus) && editor._.savedSelection) {
+					selectedElement = editor._.savedSelection.getSelectedElement();
+					ranges = !selectedElement && editor._.savedSelection.getRanges();
+
+					for(var i = 0; i < ranges.length; i++) {
+						range = ranges[i];
+						// we need to check type of node value in order to avoid error in IE when accessing 'nodeValue' property
+						if(typeof range.startContainer.$.nodeValue === 'string') {
+							textLength = range.startContainer.getText().length;
+							if(textLength < range.startOffset || textLength < range.endOffset) {
+								editor.unlockSelection(false);
+							}
+						}
+					}
+				}
+			}, this, null, -10 );	// priority "-10" is set to call SCAYT CKEDITOR.editor#unlockSelection before CKEDITOR.editor#unlockSelection call
+		};
+
+		var contentDomHandler = function() {
+			if(inline_mode) {
+
+				if (!editor.config.scayt_inlineModeImmediateMarkup) {
+					/*
+					 * Give an opportunity to CKEditor to perform all needed updates
+					 * and only after that call 'scaytDestroy' method (#72725)
+					 */
+					editor.on('blur', function () { setTimeout( scaytDestroy, 0 ); } );
+					editor.on('focus', contentDomReady);
+
+					// We need to check if editor has focus(created) right now.
+					// If editor is active - make attempt to create scayt
+					if(editor.focusManager.hasFocus) {
+						contentDomReady();
+					}
+
+				} else {
+					contentDomReady();
+				}
+
+			} else {
+				contentDomReady();
+			}
+
+			addMarkupStateHandlers();
+
+			/*
+			 * 'mousedown' handler handle widget selection (click on widget). To
+			 * fix the issue when widget#wrapper referenced to element which can
+			 * be broken after markup.
+			 */
+			var editable = editor.editable();
+			editable.attachListener(editable, 'mousedown', function( evt ) {
+				var target = evt.data.getTarget();
+				var widget = editor.widgets && editor.widgets.getByElement( target );
+				if ( widget ) {
+					widget.wrapper = target.getAscendant( function( el ) {
+						return el.hasAttribute( 'data-cke-widget-wrapper' )
+					}, true );
+				}
+			}, this, null, -10); // '-10': we need to be shure that widget#wrapper updated before any other calls
+		};
+
+		editor.on('contentDom', contentDomHandler);
+
+		editor.on('beforeCommandExec', function(ev) {
+			var scaytInstance = editor.scayt,
+				selectedLangElement = null,
+				forceBookmark = false,
+				removeMarkupInsideSelection = true;
+
+			// TODO: after switching in source mode not recreate SCAYT instance, try to just rerun markuping to don't make requests to server
+			if(ev.data.name in plugin.options.disablingCommandExec && editor.mode == 'wysiwyg') {
+				if(scaytInstance) {
+					plugin.destroy(editor);
+					editor.fire('scaytButtonState', CKEDITOR.TRISTATE_DISABLED);
+				}
+			} else if(	ev.data.name === 'bold' || ev.data.name === 'italic' || ev.data.name === 'underline' ||
+						ev.data.name === 'strike' || ev.data.name === 'subscript' || ev.data.name === 'superscript' ||
+						ev.data.name === 'enter' || ev.data.name === 'cut' || ev.data.name === 'language') {
+				if(scaytInstance) {
+					if(ev.data.name === 'cut') {
+						removeMarkupInsideSelection = false;
+						// We need to force bookmark before we remove our markup.
+						// Otherwise we will get issues with cutting text via context menu.
+						forceBookmark = true;
+					}
+
+					// We need to remove all SCAYT markup from 'lang' node before it will be deleted.
+					// We need to remove SCAYT markup from selected text before creating 'lang' node as well.
+					if(ev.data.name === 'language') {
+						selectedLangElement = editor.plugins.language.getCurrentLangElement(editor);
+						selectedLangElement = selectedLangElement && selectedLangElement.$;
+						// We need to force bookmark before we remove our markup.
+						// Otherwise we will get issues with cutting text via language plugin menu.
+						forceBookmark = true;
+					}
+
+					editor.fire('reloadMarkupScayt', {
+						removeOptions: {
+							removeInside: removeMarkupInsideSelection,
+							forceBookmark: forceBookmark,
+							selectionNode: selectedLangElement
+						},
+						timeout: 0
+					});
+				}
+			}
+		});
+
+		editor.on('beforeSetMode', function(ev) {
+			var scaytInstance;
+			// needed when we use:
+			// CKEDITOR.instances.editor_ID.setMode("source")
+			// CKEDITOR.instances.editor_ID.setMode("wysiwyg")
+			// can't be implemented in editor.on('mode', function(ev) {});
+			if (ev.data == 'source') {
+				scaytInstance = editor.scayt;
+				if(scaytInstance) {
+					plugin.destroy(editor);
+					editor.fire('scaytButtonState', CKEDITOR.TRISTATE_DISABLED);
+				}
+
+				// remove custom data from body, to prevent waste properties showing in IE8
+				if(editor.document) { //GitHub #84 : make sure that document exists(e.g. when startup mode set to 'source')
+					editor.document.getBody().removeAttribute('_jquid');
+				}
+			}
+		});
+
+		editor.on('afterCommandExec', function(ev) {
+			if(editor.mode == 'wysiwyg' && (ev.data.name == 'undo' || ev.data.name == 'redo')) {
+				setTimeout(function() {
+					var scaytInstance = editor.scayt,
+						scaytLangList = scaytInstance && scaytInstance.getScaytLangList();
+
+					/*
+					 * Checks SCAYT initialization of LangList. To prevent immediate
+					 * markup which is triggered by 'startSpellCheck' event.
+					 * E.g.: Drop into inline CKEDITOR with scayt_autoStartup = true;
+					 */
+					if (!scaytLangList || !(scaytLangList.ltr && scaytLangList.rtl)) return;
+
+					scaytInstance.fire('startSpellCheck, startGrammarCheck');
+				}, 250);
+			}
+		});
+
+		// handle readonly changes
+		editor.on('readOnly', function(ev) {
+			var scaytInstance;
+
+			if(ev) {
+				scaytInstance = editor.scayt;
+
+				if(ev.editor.readOnly === true) {
+					if(scaytInstance) {
+						scaytInstance.fire('removeMarkupInDocument', {});
+					}
+				} else {
+					if(scaytInstance) {
+						scaytInstance.fire('startSpellCheck, startGrammarCheck');
+					} else if(ev.editor.mode == 'wysiwyg' && plugin.state.scayt[ev.editor.name] === true) {
+						plugin.createScayt(editor);
+						ev.editor.fire('scaytButtonState', CKEDITOR.TRISTATE_ON);
+					}
+				}
+			}
+		});
+
+		// we need to destroy SCAYT before CK editor will be completely destroyed
+		editor.on('beforeDestroy', scaytDestroy);
+
+		//#9439 after SetData method fires contentDom event and SCAYT create additional instanse
+		// This way we should destroy SCAYT on setData event when contenteditable Iframe was re-created
+		editor.on('setData', function() {
+			scaytDestroy();
+
+			// in inline mode SetData does not fire contentDom event
+			if(editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE || editor.plugins.divarea) {
+				contentDomHandler();
+			}
+		}, this, null, 50);
+
+		/*
+		 * Main entry point to react on changes in document
+		 */
+		editor.on('reloadMarkupScayt', function(ev) {
+			var removeOptions = ev.data && ev.data.removeOptions,
+				timeout = ev.data && ev.data.timeout;
+
+			/*
+			 * Perform removeMarkupInSelectionNode and 'startSpellCheck' fire
+			 * asynchroniosly and keep CKEDITOR flow as expected
+			 */
+			setTimeout(function() {
+				var scaytInstance = editor.scayt,
+					scaytLangList = scaytInstance && scaytInstance.getScaytLangList();
+
+				/*
+				 * Checks SCAYT initialization of LangList. To prevent immediate
+				 * markup which is triggered by 'startSpellCheck' event.
+				 * E.g.: Drop into inline CKEDITOR with scayt_autoStartup = true;
+				 */
+				if (!scaytLangList || !(scaytLangList.ltr && scaytLangList.rtl)) return;
+
+				/*
+				 * CKEditor can keep \u200B character in document (with selection#selectRanges)
+				 * we need to take care about that. For this case we fire
+				 * 'keydown' [left arrow], what will trigger 'removeFillingChar' on Webkit
+				 * to cleanup the document
+				 */
+				editor.document.fire( 'keydown', new CKEDITOR.dom.event( { keyCode: 37 } ) );
+
+				/* trigger remove markup with 'startSpellCheck' */
+				scaytInstance.removeMarkupInSelectionNode(removeOptions);
+				scaytInstance.fire('startSpellCheck, startGrammarCheck');
+			}, timeout || 0 );
+		});
+
+		// Reload spell-checking for current word after insertion completed.
+		editor.on('insertElement', function() {
+			// IE bug: we need wait here to make sure that focus is returned to editor, and we can store the selection before we proceed with markup
+			editor.fire('reloadMarkupScayt', {removeOptions: {forceBookmark: true}});
+		}, this, null, 50);
+
+		editor.on('insertHtml', function() {
+			editor.fire('reloadMarkupScayt');
+		}, this, null, 50);
+
+		editor.on('insertText', function() {
+			editor.fire('reloadMarkupScayt');
+		}, this, null, 50);
+
+		// The event is listening to open necessary dialog tab
+		editor.on('scaytDialogShown', function(ev) {
+			var dialog = ev.data,
+				scaytInstance = editor.scayt;
+
+			dialog.selectPage(scaytInstance.tabToOpen);
+		});
+	},
+	parseConfig: function(editor) {
+		var plugin = CKEDITOR.plugins.scayt;
+
+		// preprocess config for backward compatibility
+		plugin.replaceOldOptionsNames(editor.config);
+
+		// Checking editor's config after initialization
+		if(typeof editor.config.scayt_autoStartup !== 'boolean') {
+			editor.config.scayt_autoStartup = false;
+		}
+		plugin.state.scayt[editor.name] = editor.config.scayt_autoStartup;
+
+		if(typeof editor.config.grayt_autoStartup !== 'boolean') {
+			editor.config.grayt_autoStartup = false;
+		}
+		if(typeof editor.config.scayt_inlineModeImmediateMarkup !== 'boolean') {
+			editor.config.scayt_inlineModeImmediateMarkup = false;
+		}
+		plugin.state.grayt[editor.name] = editor.config.grayt_autoStartup;
+
+		if(!editor.config.scayt_contextCommands) {
+			editor.config.scayt_contextCommands = 'ignore|ignoreall|add';
+		}
+
+		if(!editor.config.scayt_contextMenuItemsOrder) {
+			editor.config.scayt_contextMenuItemsOrder = 'suggest|moresuggest|control';
+		}
+
+		if(!editor.config.scayt_sLang) {
+			editor.config.scayt_sLang = 'en_US';
+		}
+
+		if(editor.config.scayt_maxSuggestions === undefined || typeof editor.config.scayt_maxSuggestions != 'number' || editor.config.scayt_maxSuggestions < 0) {
+			editor.config.scayt_maxSuggestions = 5;
+		}
+
+		if(editor.config.scayt_minWordLength === undefined || typeof editor.config.scayt_minWordLength != 'number' || editor.config.scayt_minWordLength < 1) {
+			editor.config.scayt_minWordLength = 4;
+		}
+
+		if(editor.config.scayt_customDictionaryIds === undefined || typeof editor.config.scayt_customDictionaryIds !== 'string') {
+			editor.config.scayt_customDictionaryIds = '';
+		}
+
+		if(editor.config.scayt_userDictionaryName === undefined || typeof editor.config.scayt_userDictionaryName !== 'string') {
+			editor.config.scayt_userDictionaryName = null;
+		}
+
+		if(typeof editor.config.scayt_uiTabs === 'string' && editor.config.scayt_uiTabs.split(',').length === 3) {
+			var scayt_uiTabs = [], _tempUITabs = [];
+			editor.config.scayt_uiTabs = editor.config.scayt_uiTabs.split(',');
+
+			CKEDITOR.tools.search(editor.config.scayt_uiTabs, function(value) {
+				if (Number(value) === 1 || Number(value) === 0) {
+					_tempUITabs.push(true);
+					scayt_uiTabs.push(Number(value));
+				} else {
+					_tempUITabs.push(false);
+				}
+			});
+
+			if (CKEDITOR.tools.search(_tempUITabs, false) === null) {
+				editor.config.scayt_uiTabs = scayt_uiTabs;
+			} else {
+				editor.config.scayt_uiTabs = [1,1,1];
+			}
+
+		} else {
+			editor.config.scayt_uiTabs = [1,1,1];
+		}
+
+		if(typeof editor.config.scayt_serviceProtocol != 'string') {
+			editor.config.scayt_serviceProtocol = null;
+		}
+
+		if(typeof editor.config.scayt_serviceHost != 'string') {
+			editor.config.scayt_serviceHost = null;
+		}
+
+		if(typeof editor.config.scayt_servicePort != 'string') {
+			editor.config.scayt_servicePort = null;
+		}
+
+		if(typeof editor.config.scayt_servicePath != 'string') {
+			editor.config.scayt_servicePath = null;
+		}
+
+		if(!editor.config.scayt_moreSuggestions) {
+			editor.config.scayt_moreSuggestions = 'on';
+		}
+
+		if(typeof editor.config.scayt_customerId !== 'string') {
+			editor.config.scayt_customerId = '1:WvF0D4-UtPqN1-43nkD4-NKvUm2-daQqk3-LmNiI-z7Ysb4-mwry24-T8YrS3-Q2tpq2';
+		}
+
+		if(typeof editor.config.scayt_srcUrl !== 'string') {
+			var protocol = document.location.protocol;
+			protocol = protocol.search(/https?:/) != -1 ? protocol : 'http:';
+
+			editor.config.scayt_srcUrl = protocol + '//svc.webspellchecker.net/spellcheck31/lf/scayt3/ckscayt/ckscayt.js';
+		}
+
+		if(typeof CKEDITOR.config.scayt_handleCheckDirty !== 'boolean') {
+			CKEDITOR.config.scayt_handleCheckDirty = true;
+		}
+
+		if(typeof CKEDITOR.config.scayt_handleUndoRedo !== 'boolean') {
+			/* set default as 'true' */
+			CKEDITOR.config.scayt_handleUndoRedo = true;
+		}
+		/* checking 'undo' plugin, if no disable SCAYT handler */
+		CKEDITOR.config.scayt_handleUndoRedo = CKEDITOR.plugins.undo ? CKEDITOR.config.scayt_handleUndoRedo : false;
+
+		if(typeof editor.config.scayt_multiLanguageMode !== 'boolean') {
+			editor.config.scayt_multiLanguageMode = false;
+		}
+
+		if(typeof editor.config.scayt_multiLanguageStyles !== 'object') {
+			editor.config.scayt_multiLanguageStyles = {};
+		}
+
+		if(editor.config.scayt_ignoreAllCapsWords && typeof editor.config.scayt_ignoreAllCapsWords !== 'boolean') {
+			editor.config.scayt_ignoreAllCapsWords = false;
+		}
+
+		if(editor.config.scayt_ignoreDomainNames && typeof editor.config.scayt_ignoreDomainNames !== 'boolean') {
+			editor.config.scayt_ignoreDomainNames = false;
+		}
+
+		if(editor.config.scayt_ignoreWordsWithMixedCases && typeof editor.config.scayt_ignoreWordsWithMixedCases !== 'boolean') {
+			editor.config.scayt_ignoreWordsWithMixedCases = false;
+		}
+
+		if(editor.config.scayt_ignoreWordsWithNumbers && typeof editor.config.scayt_ignoreWordsWithNumbers !== 'boolean') {
+			editor.config.scayt_ignoreWordsWithNumbers = false;
+		}
+
+		if( editor.config.scayt_disableOptionsStorage ) {
+			var userOptions = CKEDITOR.tools.isArray( editor.config.scayt_disableOptionsStorage ) ? editor.config.scayt_disableOptionsStorage : ( typeof editor.config.scayt_disableOptionsStorage === 'string' ) ? [ editor.config.scayt_disableOptionsStorage ] : undefined,
+				availableValue = [ 'all', 'options', 'lang', 'ignore-all-caps-words', 'ignore-domain-names', 'ignore-words-with-mixed-cases', 'ignore-words-with-numbers'],
+				valuesOption = ['lang', 'ignore-all-caps-words', 'ignore-domain-names', 'ignore-words-with-mixed-cases', 'ignore-words-with-numbers'],
+				search = CKEDITOR.tools.search,
+				indexOf = CKEDITOR.tools.indexOf;
+
+			var isValidOption = function( option ) {
+				return !!search( availableValue, option );
+			};
+
+			var makeOptionsToStorage = function( options ) {
+				var retval = [];
+
+				for (var i = 0; i < options.length; i++) {
+					var value = options[i],
+						isGroupOptionInUserOptions = !!search( options, 'options' );
+
+					if( !isValidOption( value ) || isGroupOptionInUserOptions && !!search( valuesOption, function( val ) { if( val === 'lang' ) { return false; } } ) ) {
+						return;
+					}
+
+					if( !!search( valuesOption, value ) ) {
+						valuesOption.splice( indexOf( valuesOption, value ), 1 );
+					}
+
+					if(  value === 'all' || isGroupOptionInUserOptions && !!search( options, 'lang' )) {
+						return [];
+					}
+
+					if( value === 'options' ) {
+						valuesOption = [ 'lang' ];
+					}
+				}
+
+				retval = retval.concat( valuesOption );
+
+				return retval;
+			};
+
+			editor.config.scayt_disableOptionsStorage = makeOptionsToStorage( userOptions );
+		}
+	},
+	addRule: function(editor) {
+		var plugin = CKEDITOR.plugins.scayt,
+			dataProcessor = editor.dataProcessor,
+			htmlFilter = dataProcessor && dataProcessor.htmlFilter,
+			pathFilters = editor._.elementsPath && editor._.elementsPath.filters,
+			dataFilter = dataProcessor && dataProcessor.dataFilter,
+			removeFormatFilter = editor.addRemoveFormatFilter,
+			pathFilter = function(element) {
+				var scaytInstance = editor.scayt;
+
+				if( scaytInstance && (element.hasAttribute(plugin.options.data_attribute_name) || element.hasAttribute(plugin.options.problem_grammar_data_attribute)) ) {
+					return false;
+				}
+			},
+			removeFormatFilterTemplate = function(element) {
+				var scaytInstance = editor.scayt,
+					result = true;
+
+				if( scaytInstance && (element.hasAttribute(plugin.options.data_attribute_name) || element.hasAttribute(plugin.options.problem_grammar_data_attribute)) ) {
+					result = false;
+				}
+
+				return result;
+			};
+
+		if(pathFilters) {
+			pathFilters.push(pathFilter);
+		}
+
+		if(dataFilter) {
+			var dataFilterRules = {
+				elements: {
+					span: function(element) {
+
+						var scaytState = element.hasClass(plugin.options.misspelled_word_class) && element.attributes[plugin.options.data_attribute_name],
+							graytState = element.hasClass(plugin.options.problem_grammar_class) && element.attributes[plugin.options.problem_grammar_data_attribute];
+
+						if(plugin && (scaytState || graytState)) {
+							delete element.name;
+						}
+
+						return element;
+					}
+				}
+			};
+
+			dataFilter.addRules(dataFilterRules);
+		}
+
+		if (htmlFilter) {
+			var htmlFilterRules = {
+				elements: {
+					span: function(element) {
+
+						var scaytState = element.hasClass(plugin.options.misspelled_word_class) && element.attributes[plugin.options.data_attribute_name],
+							graytState = element.hasClass(plugin.options.problem_grammar_class) && element.attributes[plugin.options.problem_grammar_data_attribute];
+
+						if(plugin && (scaytState || graytState)) {
+							delete element.name;
+						}
+
+						return element;
+					}
+				}
+			};
+
+			htmlFilter.addRules(htmlFilterRules);
+		}
+
+		if(removeFormatFilter) {
+			removeFormatFilter.call(editor, removeFormatFilterTemplate);
+		}
+	},
+	scaytMenuDefinition: function(editor) {
+		var self = this,
+			plugin = CKEDITOR.plugins.scayt,
+			scayt_instance =  editor.scayt;
+
+		return {
+			scayt: {
+				scayt_ignore: {
+					label:  scayt_instance.getLocal('btn_ignore'),
+					group : 'scayt_control',
+					order : 1,
+					exec: function(editor) {
+						var scaytInstance = editor.scayt;
+						scaytInstance.ignoreWord();
+					}
+				},
+				scayt_ignoreall: {
+					label : scayt_instance.getLocal('btn_ignoreAll'),
+					group : 'scayt_control',
+					order : 2,
+					exec: function(editor) {
+						var scaytInstance = editor.scayt;
+						scaytInstance.ignoreAllWords();
+					}
+				},
+				scayt_add: {
+					label : scayt_instance.getLocal('btn_addWord'),
+					group : 'scayt_control',
+					order : 3,
+					exec : function(editor) {
+						var scaytInstance = editor.scayt;
+
+						// @TODO: We need to add set/restore bookmark logic to 'addWordToUserDictionary' method inside dictionarymanager.
+						// Timeout is used as tmp fix for IE9, when after hitting 'Add word' menu item, document container was blurred.
+						setTimeout(function() {
+							scaytInstance.addWordToUserDictionary();
+						}, 10);
+					}
+				},
+				scayt_option: {
+					label : scayt_instance.getLocal('btn_options'),
+					group : 'scayt_control',
+					order : 4,
+					exec: function(editor) {
+						var scaytInstance = editor.scayt;
+
+						scaytInstance.tabToOpen = 'options';
+						editor.lockSelection();
+						editor.openDialog(self.dialogName);
+					},
+					verification: function(editor) {
+						return (editor.config.scayt_uiTabs[0] == 1) ? true : false;
+					}
+				},
+				scayt_language: {
+					label : scayt_instance.getLocal('btn_langs'),
+					group : 'scayt_control',
+					order : 5,
+					exec: function(editor) {
+						var scaytInstance = editor.scayt;
+
+						scaytInstance.tabToOpen = 'langs';
+						editor.lockSelection();
+						editor.openDialog(self.dialogName);
+					},
+					verification: function(editor) {
+						return (editor.config.scayt_uiTabs[1] == 1) ? true : false;
+					}
+				},
+				scayt_dictionary: {
+					label : scayt_instance.getLocal('btn_dictionaries'),
+					group : 'scayt_control',
+					order : 6,
+					exec: function(editor) {
+						var scaytInstance = editor.scayt;
+
+						scaytInstance.tabToOpen = 'dictionaries';
+						editor.lockSelection();
+						editor.openDialog(self.dialogName);
+					},
+					verification: function(editor) {
+						return (editor.config.scayt_uiTabs[2] == 1) ? true : false;
+					}
+				},
+				scayt_about: {
+					label : scayt_instance.getLocal('btn_about'),
+					group : 'scayt_control',
+					order : 7,
+					exec: function(editor) {
+						var scaytInstance = editor.scayt;
+
+						scaytInstance.tabToOpen = 'about';
+						editor.lockSelection();
+						editor.openDialog(self.dialogName);
+					}
+				}
+			},
+			grayt: {
+				grayt_problemdescription: {
+					label : 'Grammar problem description',
+					group : 'grayt_description', // look at addMenuItems method for further info
+					order : 1,
+					state : CKEDITOR.TRISTATE_DISABLED,
+					exec: function(editor) {}
+				},
+				grayt_ignore: {
+					label : scayt_instance.getLocal('btn_ignore'),
+					group : 'grayt_control',
+					order : 2,
+					exec: function(editor) {
+						var scaytInstance = editor.scayt;
+
+						scaytInstance.ignorePhrase();
+					}
+				}
+			}
+		};
+	},
+	buildSuggestionMenuItems: function(editor, suggestions, isScaytNode) {
+		var self = this,
+			itemList = {},
+			subItemList = {},
+			replaceKeyName = isScaytNode ? 'word' : 'phrase',
+			updateEventName = isScaytNode ? 'startGrammarCheck' : 'startSpellCheck',
+			plugin = CKEDITOR.plugins.scayt,
+			scayt_instance = editor.scayt;
+
+		if(suggestions.length > 0 && suggestions[0] !== 'no_any_suggestions') {
+
+			if(isScaytNode) {
+				// build SCAYT suggestions
+				for(var i = 0; i < suggestions.length; i++) {
+
+					var commandName = 'scayt_suggest_' + CKEDITOR.plugins.scayt.suggestions[i].replace(' ', '_');
+
+					editor.addCommand(commandName, self.createCommand(CKEDITOR.plugins.scayt.suggestions[i], replaceKeyName, updateEventName));
+
+					if(i < editor.config.scayt_maxSuggestions) {
+
+						// mainSuggestions
+						editor.addMenuItem(commandName, {
+							label: suggestions[i],
+							command: commandName,
+							group: 'scayt_suggest',
+							order: i + 1
+						});
+
+						itemList[commandName] = CKEDITOR.TRISTATE_OFF;
+
+					} else {
+
+						// moreSuggestions
+						editor.addMenuItem(commandName, {
+							label: suggestions[i],
+							command: commandName,
+							group: 'scayt_moresuggest',
+							order: i + 1
+						});
+
+						subItemList[commandName] = CKEDITOR.TRISTATE_OFF;
+
+						if(editor.config.scayt_moreSuggestions === 'on') {
+
+							editor.addMenuItem('scayt_moresuggest', {
+								label : scayt_instance.getLocal('btn_moreSuggestions'),
+								group : 'scayt_moresuggest',
+								order : 10,
+								getItems : function() {
+									return subItemList;
+								}
+							});
+
+							itemList['scayt_moresuggest'] = CKEDITOR.TRISTATE_OFF;
+						}
+					}
+				}
+			} else {
+				// build GRAYT suggestions
+				for(var i = 0; i < suggestions.length; i++) {
+					var commandName = 'grayt_suggest_' + CKEDITOR.plugins.scayt.suggestions[i].replace(' ', '_');
+
+					editor.addCommand(commandName, self.createCommand(CKEDITOR.plugins.scayt.suggestions[i], replaceKeyName, updateEventName));
+
+					// mainSuggestions
+					editor.addMenuItem(commandName, {
+						label: suggestions[i],
+						command: commandName,
+						group: 'grayt_suggest',
+						order: i + 1
+					});
+
+					itemList[commandName] = CKEDITOR.TRISTATE_OFF;
+				}
+			}
+		} else {
+			var noSuggestionsCommand = 'no_scayt_suggest';
+			itemList[noSuggestionsCommand] = CKEDITOR.TRISTATE_DISABLED;
+
+			editor.addCommand(noSuggestionsCommand, {
+				exec: function() {
+
+				}
+			});
+
+			editor.addMenuItem(noSuggestionsCommand, {
+				label : scayt_instance.getLocal('btn_noSuggestions') || noSuggestionsCommand,
+				command: noSuggestionsCommand,
+				group : 'scayt_suggest',
+				order : 0
+			});
+		}
+
+		return itemList;
+	},
+	menuGenerator: function(editor, selectionNode) {
+		var self = this,
+			scaytInstance = editor.scayt,
+			menuItems = this.scaytMenuDefinition(editor),
+			itemList = {},
+			allowedOption = editor.config.scayt_contextCommands.split('|'),
+			lang = selectionNode.getAttribute(scaytInstance.getLangAttribute()) || scaytInstance.getLang(),
+			word, grammarPhrase, isScaytNode, isGrammarNode, problemDescriptionText;
+
+
+		isScaytNode = scaytInstance.isScaytNode(selectionNode);
+		isGrammarNode = scaytInstance.isGraytNode(selectionNode);
+
+		if(isScaytNode) {
+			// we clicked scayt misspelling
+			// get suggestions
+			menuItems = menuItems.scayt;
+
+			word = selectionNode.getAttribute(scaytInstance.getScaytNodeAttributeName());
+
+			scaytInstance.fire('getSuggestionsList', {
+				lang: lang,
+				word: word
+			});
+
+			itemList = this.buildSuggestionMenuItems(editor, CKEDITOR.plugins.scayt.suggestions, isScaytNode);
+		} else if(isGrammarNode) {
+			// we clicked grammar problem
+			// get suggestions
+			menuItems = menuItems.grayt;
+			grammarPhrase = selectionNode.getAttribute(scaytInstance.getGraytNodeAttributeName());
+
+			// setup grammar problem description
+			problemDescriptionText = scaytInstance.getProblemDescriptionText(grammarPhrase, lang);
+			if(menuItems.grayt_problemdescription && problemDescriptionText) {
+				menuItems.grayt_problemdescription.label = problemDescriptionText;
+			}
+
+			scaytInstance.fire('getGrammarSuggestionsList', {
+				lang: lang,
+				phrase: grammarPhrase
+			});
+
+			itemList = this.buildSuggestionMenuItems(editor, CKEDITOR.plugins.scayt.suggestions, isScaytNode);
+		}
+
+		if(isScaytNode && editor.config.scayt_contextCommands == 'off') {
+			return itemList;
+		}
+
+		for(var key in menuItems) {
+			if(isScaytNode && CKEDITOR.tools.indexOf(allowedOption, key.replace('scayt_', '')) == -1 && editor.config.scayt_contextCommands != 'all') {
+				continue;
+			}
+
+			if(typeof menuItems[key].state != 'undefined') {
+				itemList[key] = menuItems[key].state;
+			} else {
+				itemList[key] = CKEDITOR.TRISTATE_OFF;
+			}
+
+			// delete item from context menu if its state isn't verified as allowed
+			if(typeof menuItems[key].verification === 'function' && !menuItems[key].verification(editor)) {
+				// itemList[key] = (menuItems[key].verification(editor)) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED;
+				delete itemList[key];
+			}
+
+			editor.addCommand(key, {
+				exec: menuItems[key].exec
+			});
+
+			editor.addMenuItem(key, {
+				label : editor.lang.scayt[menuItems[key].label] || menuItems[key].label,
+				command: key,
+				group : menuItems[key].group,
+				order : menuItems[key].order
+			});
+		}
+
+		return itemList;
+	},
+	createCommand: function(suggestion, replaceKeyName, updateEventName) {
+		return {
+			exec: function(editor) {
+				var scaytInstance = editor.scayt,
+					eventObject = {};
+
+				eventObject[replaceKeyName] = suggestion;
+				scaytInstance.replaceSelectionNode(eventObject);
+
+				// we need to remove grammar markup from selection node if we just performed replace action for misspelling
+				if(updateEventName === 'startGrammarCheck') {
+					scaytInstance.removeMarkupInSelectionNode({grammarOnly: true});
+				}
+				// for grayt problem replacement we need to fire 'startSpellCheck'
+				// for scayt misspelling replacement we need to fire 'startGrammarCheck'
+				scaytInstance.fire(updateEventName);
+			}
+		};
+	}
+});
+
+CKEDITOR.plugins.scayt = {
+	state: {
+		scayt: {},
+		grayt: {}
+	},
+	suggestions: [],
+	loadingHelper: {
+		loadOrder: []
+	},
+	isLoading: false,
+	options: {
+		disablingCommandExec: {
+			source: true,
+			newpage: true,
+			templates: true
+		},
+		data_attribute_name: 'data-scayt-word',
+		misspelled_word_class: 'scayt-misspell-word',
+		problem_grammar_data_attribute: 'data-grayt-phrase',
+		problem_grammar_class: 'gramm-problem'
+	},
+	backCompatibilityMap: {
+		'scayt_service_protocol': 'scayt_serviceProtocol',
+		'scayt_service_host'  : 'scayt_serviceHost',
+		'scayt_service_port'  : 'scayt_servicePort',
+		'scayt_service_path'  : 'scayt_servicePath',
+		'scayt_customerid'    : 'scayt_customerId'
+	},
+	replaceOldOptionsNames: function(config) {
+		for(var key in config) {
+			if(key in this.backCompatibilityMap) {
+				config[this.backCompatibilityMap[key]] = config[key];
+				delete config[key];
+			}
+		}
+	},
+	createScayt : function(editor) {
+		var self = this,
+			plugin = CKEDITOR.plugins.scayt;
+
+		this.loadScaytLibrary(editor, function(_editor) {
+			var textContainer = _editor.window && _editor.window.getFrame() || _editor.editable();
+
+			// Do not create SCAYT if there is no text container for usage
+			if(!textContainer) {
+				plugin.state.scayt[_editor.name] = false;
+				return;
+			}
+
+			var scaytInstanceOptions = {
+				lang 				: _editor.config.scayt_sLang,
+				container 			: textContainer.$,
+				customDictionary 	: _editor.config.scayt_customDictionaryIds,
+				userDictionaryName 	: _editor.config.scayt_userDictionaryName,
+				localization 		: _editor.langCode,
+				customer_id 		: _editor.config.scayt_customerId,
+				debug 				: _editor.config.scayt_debug,
+				data_attribute_name : self.options.data_attribute_name,
+				misspelled_word_class: self.options.misspelled_word_class,
+				problem_grammar_data_attribute: self.options.problem_grammar_data_attribute,
+				problem_grammar_class: self.options.problem_grammar_class,
+				'options-to-restore':  _editor.config.scayt_disableOptionsStorage,
+				focused 			: _editor.editable().hasFocus, // #30260 we need to set focused=true if CKEditor is focused before SCAYT initialization
+				ignoreElementsRegex : _editor.config.scayt_elementsToIgnore,
+				minWordLength 		: _editor.config.scayt_minWordLength,
+				multiLanguageMode 	: _editor.config.scayt_multiLanguageMode,
+				multiLanguageStyles	: _editor.config.scayt_multiLanguageStyles,
+				graytAutoStartup	: plugin.state.grayt[_editor.name]
+			};
+
+			if(_editor.config.scayt_serviceProtocol) {
+				scaytInstanceOptions['service_protocol'] = _editor.config.scayt_serviceProtocol;
+			}
+
+			if(_editor.config.scayt_serviceHost) {
+				scaytInstanceOptions['service_host'] = _editor.config.scayt_serviceHost;
+			}
+
+			if(_editor.config.scayt_servicePort) {
+				scaytInstanceOptions['service_port'] = _editor.config.scayt_servicePort;
+			}
+
+			if(_editor.config.scayt_servicePath) {
+				scaytInstanceOptions['service_path'] = _editor.config.scayt_servicePath;
+			}
+
+			//predefined options
+			if(typeof _editor.config.scayt_ignoreAllCapsWords === 'boolean') {
+				scaytInstanceOptions['ignore-all-caps-words'] = _editor.config.scayt_ignoreAllCapsWords;
+			}
+
+			if(typeof _editor.config.scayt_ignoreDomainNames === 'boolean') {
+				scaytInstanceOptions['ignore-domain-names'] = _editor.config.scayt_ignoreDomainNames;
+			}
+
+			if(typeof _editor.config.scayt_ignoreWordsWithMixedCases === 'boolean') {
+				scaytInstanceOptions['ignore-words-with-mixed-cases'] = _editor.config.scayt_ignoreWordsWithMixedCases;
+			}
+
+			if(typeof _editor.config.scayt_ignoreWordsWithNumbers === 'boolean') {
+				scaytInstanceOptions['ignore-words-with-numbers'] = _editor.config.scayt_ignoreWordsWithNumbers;
+			}
+
+			var scaytInstance = new SCAYT.CKSCAYT(scaytInstanceOptions, function() {
+					// success callback
+				}, function() {
+					// error callback
+				}),
+				wordsPrefix = 'word_';
+
+			scaytInstance.subscribe('suggestionListSend', function(data) {
+				// TODO: 1. Maybe store suggestions for specific editor
+				// TODO: 2. Fix issue with suggestion duplicates on on server
+				//CKEDITOR.plugins.scayt.suggestions = data.suggestionList;
+				var _wordsCollection = {},
+					_suggestionList =[];
+
+				for (var i = 0; i < data.suggestionList.length; i++) {
+					if (!_wordsCollection[wordsPrefix + data.suggestionList[i]]) {
+						_wordsCollection[wordsPrefix + data.suggestionList[i]] = data.suggestionList[i];
+						_suggestionList.push(data.suggestionList[i]);
+					}
+				}
+
+				CKEDITOR.plugins.scayt.suggestions = _suggestionList;
+			});
+
+			// if selection has changed programmatically by SCAYT we need to react appropriately
+			scaytInstance.subscribe('selectionIsChanged', function(data) {
+				var selection = _editor.getSelection();
+
+				if(selection.isLocked) {
+					_editor.lockSelection();
+				}
+			});
+
+			scaytInstance.subscribe('graytStateChanged', function(data) {
+				plugin.state.grayt[_editor.name] = data.state;
+			});
+
+			_editor.scayt = scaytInstance;
+
+			_editor.fire('scaytButtonState', _editor.readOnly ? CKEDITOR.TRISTATE_DISABLED : CKEDITOR.TRISTATE_ON);
+		});
+	},
+	destroy: function(editor) {
+		if(editor.scayt) {
+			editor.scayt.destroy();
+		}
+
+		delete editor.scayt;
+		editor.fire('scaytButtonState', CKEDITOR.TRISTATE_OFF);
+	},
+	loadScaytLibrary: function(editor, callback) {
+		var self = this,
+			date,
+			timestamp,
+			scaytUrl;
+
+		// no need to process load requests from same editor as it can cause bugs with
+		// loading ckscayt app due to subsequent calls of some events
+		// need to be before 'if' statement, because of timing issue in CKEDITOR.scriptLoader
+		// when callback executing is delayed for a few milliseconds, and scayt can be created twise
+		// on one instance
+		if(this.loadingHelper[editor.name]) return;
+
+		if(typeof window.SCAYT === 'undefined' || typeof window.SCAYT.CKSCAYT !== 'function') {
+
+			// add onLoad callbacks for editors while SCAYT is loading
+			this.loadingHelper[editor.name] = callback;
+			this.loadingHelper.loadOrder.push(editor.name);
+
+			//creating unique timestamp for SCAYT URL
+			date = new Date();
+			timestamp = date.getTime();
+			scaytUrl = editor.config.scayt_srcUrl;
+
+			//if there already implemented timstamp for scayr_srcURL use it, if not use our timestamp
+			scaytUrl = scaytUrl + (scaytUrl.indexOf('?') >= 0 ? '' : '?' + timestamp);
+
+			if (!this.loadingHelper.ckscaytLoading) {
+				CKEDITOR.scriptLoader.load(scaytUrl, function(success) {
+					var editorName;
+
+					if ( success ) {
+						CKEDITOR.fireOnce('scaytReady');
+
+						for(var i = 0; i < self.loadingHelper.loadOrder.length; i++) {
+							editorName = self.loadingHelper.loadOrder[i];
+
+							if(typeof self.loadingHelper[editorName] === 'function') {
+								self.loadingHelper[editorName](CKEDITOR.instances[editorName]);
+							}
+
+							delete self.loadingHelper[editorName];
+						}
+						self.loadingHelper.loadOrder = [];
+					}
+				});
+				this.loadingHelper.ckscaytLoading = true;
+			}
+
+
+		} else if(window.SCAYT && typeof window.SCAYT.CKSCAYT === 'function') {
+			CKEDITOR.fireOnce('scaytReady');
+
+			if(!editor.scayt) {
+				if(typeof callback === 'function') {
+					callback(editor);
+				}
+			}
+		}
+	}
+};
+
+CKEDITOR.on('dialogDefinition', function(dialogDefinitionEvent) {
+	var dialogName = dialogDefinitionEvent.data.name,
+		dialogDefinition = dialogDefinitionEvent.data.definition,
+		dialog = dialogDefinition.dialog;
+
+	if (dialogName === 'scaytDialog') {
+		dialog.on('cancel', function(cancelEvent) {
+			return false;
+		}, this, null, -1);
+	}
+
+	if ( dialogName === 'checkspell' ) {
+		dialog.on( 'cancel', function( cancelEvent ) {
+			var editor = cancelEvent.sender && cancelEvent.sender.getParentEditor(),
+				plugin = CKEDITOR.plugins.scayt,
+				scaytInstance = editor.scayt;
+
+			if ( scaytInstance && plugin.state.scayt[ editor.name ] && scaytInstance.setMarkupPaused ) {
+				scaytInstance.setMarkupPaused( false );
+			}
+
+			editor.unlockSelection();
+		}, this, null, -2 ); // we need to call cancel callback before WSC plugin
+	}
+
+	if (dialogName === 'link') {
+		dialog.on('ok', function(okEvent) {
+			var editor = okEvent.sender && okEvent.sender.getParentEditor();
+
+			if(editor) {
+				setTimeout(function() {
+					editor.fire('reloadMarkupScayt', {
+						removeOptions: {
+							removeInside: true,
+							forceBookmark: true
+						},
+						timeout: 0
+					});
+				}, 0);
+			}
+		});
+	}
+});
+
+CKEDITOR.on('scaytReady', function() {
+
+	// Override editor.checkDirty method avoid CK checkDirty functionality to fix SCAYT issues with incorrect checkDirty behavior.
+	if(CKEDITOR.config.scayt_handleCheckDirty === true) {
+		var editorCheckDirty = CKEDITOR.editor.prototype;
+
+		editorCheckDirty.checkDirty = CKEDITOR.tools.override(editorCheckDirty.checkDirty, function(org) {
+
+			return function() {
+				var retval = null,
+					pluginStatus = CKEDITOR.plugins.scayt && CKEDITOR.plugins.scayt.state.scayt[this.name] && this.scayt,
+					scaytInstance = this.scayt;
+
+				if(!pluginStatus) {
+					retval = org.call(this);
+				} else {
+					retval = (this.status == 'ready');
+
+					if (retval) {
+						var currentData = scaytInstance.removeMarkupFromString(this.getSnapshot()),
+							prevData = scaytInstance.removeMarkupFromString(this._.previousValue);
+
+						retval = (retval && (prevData !== currentData))
+					}
+				}
+
+				return retval;
+			};
+		});
+
+		editorCheckDirty.resetDirty = CKEDITOR.tools.override(editorCheckDirty.resetDirty, function(org) {
+			return function() {
+				var pluginStatus = CKEDITOR.plugins.scayt && CKEDITOR.plugins.scayt.state.scayt[this.name] && this.scayt,
+					scaytInstance = this.scayt;//CKEDITOR.plugins.scayt.getScayt(this);
+
+				if(!pluginStatus) {
+					org.call(this);
+				} else {
+					this._.previousValue = scaytInstance.removeMarkupFromString(this.getSnapshot());
+				}
+			};
+		});
+	}
+
+	if (CKEDITOR.config.scayt_handleUndoRedo === true) {
+		var undoImagePrototype = CKEDITOR.plugins.undo.Image.prototype;
+
+		// add backword compatibility for CKEDITOR 4.2. method equals was repleced on other method
+		var equalsContentMethodName = (typeof undoImagePrototype.equalsContent == "function") ? 'equalsContent' : 'equals';
+
+		undoImagePrototype[equalsContentMethodName] = CKEDITOR.tools.override(undoImagePrototype[equalsContentMethodName], function(org) {
+			return function(otherImage) {
+				var pluginState = CKEDITOR.plugins.scayt && CKEDITOR.plugins.scayt.state.scayt[otherImage.editor.name] && otherImage.editor.scayt,
+					scaytInstance = otherImage.editor.scayt,
+					thisContents = this.contents,
+					otherContents = otherImage.contents,
+					retval = null;
+
+				// Making the comparison based on content without SCAYT word markers.
+				if(pluginState) {
+					this.contents = scaytInstance.removeMarkupFromString(thisContents) || '';
+					otherImage.contents = scaytInstance.removeMarkupFromString(otherContents) || '';
+				}
+
+				var retval = org.apply(this, arguments);
+
+				this.contents = thisContents;
+				otherImage.contents = otherContents;
+
+				return retval;
+			};
+		});
+	}
+});
+
+/**
+ * Automatically enables SCAYT on editor startup. When set to `true`, this option turns on SCAYT automatically
+ * after loading the editor.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		config.scayt_autoStartup = true;
+ *
+ * @cfg {Boolean} [scayt_autoStartup=false]
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Enables Grammar As You Type (GRAYT) on SCAYT startup. When set to `true`, this option turns on GRAYT automatically
+ * after SCAYT started.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		config.grayt_autoStartup = true;
+ *
+ * @since 4.5.6
+ * @cfg {Boolean} [grayt_autoStartup=false]
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Enables SCAYT initialization when inline CKEditor is not focused. When set to `true`, SCAYT markup is
+ * displayed in both inline editor states, focused and unfocused, so the SCAYT instance is not destroyed. 
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		 config.scayt_inlineModeImmediateMarkup = true;
+ *
+ * @since 4.5.6
+ * @cfg {Boolean} [scayt_inlineModeImmediateMarkup=false]
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Defines the number of SCAYT suggestions to show in the main context menu.
+ * Possible values are:
+ *
+ * * `0` (zero) &ndash; No suggestions are shown in the main context menu. All
+ *     entries will be listed in the "More Suggestions" sub-menu.
+ * * Positive number &ndash; The maximum number of suggestions to show in the context
+ *     menu. Other entries will be shown in the "More Suggestions" sub-menu.
+ * * Negative number &ndash; Five suggestions are shown in the main context menu. All other
+ *     entries will be listed in the "More Suggestions" sub-menu.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ * Examples:
+ *
+ *		// Display only three suggestions in the main context menu.
+ *		config.scayt_maxSuggestions = 3;
+ *
+ *		// Do not show the suggestions directly.
+ *		config.scayt_maxSuggestions = 0;
+ *
+ * @cfg {Number} [scayt_maxSuggestions=5]
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Defines the minimum length of words that will be collected from the editor content for spell checking.
+ * Possible value is any positive number.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ * Examples:
+ *
+ *		// Set the minimum length of words that will be collected from editor text.
+ *		config.scayt_minWordLength = 5;
+ *
+ * @cfg {Number} [scayt_minWordLength=4]
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Sets the customer ID for SCAYT. Used for hosted users only. Required for migration from free
+ * to trial or paid versions.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		// Load SCAYT using my customer ID.
+ *		config.scayt_customerId  = 'your-encrypted-customer-id';
+ *
+ * @cfg {String} [scayt_customerId='1:WvF0D4-UtPqN1-43nkD4-NKvUm2-daQqk3-LmNiI-z7Ysb4-mwry24-T8YrS3-Q2tpq2']
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Enables and disables the "More Suggestions" sub-menu in the context menu.
+ * Possible values are `'on'` and `'off'`.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		// Disables the "More Suggestions" sub-menu.
+ *		config.scayt_moreSuggestions = 'off';
+ *
+ * @cfg {String} [scayt_moreSuggestions='on']
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Customizes the display of SCAYT context menu commands ("Add Word", "Ignore",
+ * "Ignore All", "Options", "Languages", "Dictionaries" and "About").
+ * This must be a string with one or more of the following
+ * words separated by a pipe character (`'|'`):
+ *
+ * * `off` &ndash; Disables all options.
+ * * `all` &ndash; Enables all options.
+ * * `ignore` &ndash; Enables the "Ignore" option.
+ * * `ignoreall` &ndash; Enables the "Ignore All" option.
+ * * `add` &ndash; Enables the "Add Word" option.
+ * * `option` &ndash; Enables the "Options" menu item.
+ * * `language` &ndash; Enables the "Languages" menu item.
+ * * `dictionary` &ndash; Enables the "Dictionaries" menu item.
+ * * `about` &ndash; Enables the "About" menu item.
+ *
+ * Please note that availability of the "Options", "Languages" and "Dictionaries" items
+ * also depends on the {@link CKEDITOR.config#scayt_uiTabs} option.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ * Example:
+ *
+ *		// Show only "Add Word" and "Ignore All" in the context menu.
+ *		config.scayt_contextCommands = 'add|ignoreall';
+ *
+ * @cfg {String} [scayt_contextCommands='ignore|ignoreall|add']
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Sets the default spell checking language for SCAYT. Possible values are:
+ * `'en_US'`, `'en_GB'`, `'pt_BR'`, `'da_DK'`,
+ * `'nl_NL'`, `'en_CA'`, `'fi_FI'`, `'fr_FR'`,
+ * `'fr_CA'`, `'de_DE'`, `'el_GR'`, `'it_IT'`,
+ * `'nb_NO'`, `'pt_PT'`, `'es_ES'`, `'sv_SE'`.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		// Sets SCAYT to German.
+ *		config.scayt_sLang = 'de_DE';
+ *
+ * @cfg {String} [scayt_sLang='en_US']
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Customizes the SCAYT dialog and SCAYT toolbar menu to show particular tabs and items.
+ * This setting must contain a `1` (enabled) or `0`
+ * (disabled) value for each of the following entries, in this precise order,
+ * separated by a comma (`','`): `'Options'`, `'Languages'`, and `'Dictionary'`.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		// Hides the "Languages" tab.
+ *		config.scayt_uiTabs = '1,0,1';
+ *
+ * @cfg {String} [scayt_uiTabs='1,1,1']
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Sets the protocol for the WebSpellChecker service (`ssrv.cgi`) full path.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		// Defines the protocol for the WebSpellChecker service (ssrv.cgi) path.
+ *		config.scayt_serviceProtocol = 'https';
+ *
+ * @cfg {String} [scayt_serviceProtocol='http']
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Sets the host for the WebSpellChecker service (`ssrv.cgi`) full path.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		// Defines the host for the WebSpellChecker service (ssrv.cgi) path.
+ *		config.scayt_serviceHost = 'my-host';
+ *
+ * @cfg {String} [scayt_serviceHost='svc.webspellchecker.net']
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Sets the port for the WebSpellChecker service (`ssrv.cgi`) full path.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		// Defines the port for the WebSpellChecker service (ssrv.cgi) path.
+ *		config.scayt_servicePort = '2330';
+ *
+ * @cfg {String} [scayt_servicePort='80']
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Sets the path to the WebSpellChecker service (`ssrv.cgi`).
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		// Defines the path to the WebSpellChecker service (ssrv.cgi).
+ *		config.scayt_servicePath = 'my-path/ssrv.cgi';
+ *
+ * @cfg {String} [scayt_servicePath='spellcheck31/script/ssrv.cgi']
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Sets the URL to SCAYT core. Required to switch to the licensed version of SCAYT.
+ *
+ * Refer to [SCAYT documentation](http://wiki.webspellchecker.net/doku.php?id=migration:hosredfreetolicensedck)
+ * for more details.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		config.scayt_srcUrl = "http://my-host/spellcheck/lf/scayt/scayt.js";
+ *
+ * @cfg {String} [scayt_srcUrl='//svc.webspellchecker.net/spellcheck31/lf/scayt3/ckscayt/ckscayt.js']
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Links SCAYT to custom dictionaries. This is a string containing the dictionary IDs
+ * separated by commas (`','`). Available only for the licensed version.
+ *
+ * Refer to [SCAYT documentation](http://wiki.webspellchecker.net/doku.php?id=installationandconfiguration:customdictionaries:licensed)
+ * for more details.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		config.scayt_customDictionaryIds = '3021,3456,3478';
+ *
+ * @cfg {String} [scayt_customDictionaryIds='']
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Activates a User Dictionary in SCAYT. The user
+ * dictionary name must be used. Available only for the licensed version.
+ *
+ * Refer to [SCAYT documentation](http://wiki.webspellchecker.net/doku.php?id=installationandconfiguration:userdictionaries)
+ * for more details. 
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		config.scayt_userDictionaryName = 'MyDictionary';
+ *
+ * @cfg {String} [scayt_userDictionaryName='']
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Defines the order of SCAYT context menu items by groups.
+ * This must be a string with one or more of the following
+ * words separated by a pipe character (`'|'`):
+ *
+ * * `suggest` &ndash; The main suggestion word list.
+ * * `moresuggest` &ndash; The "More suggestions" word list.
+ * * `control` &ndash; SCAYT commands, such as "Ignore" and "Add Word".
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ * Example:
+ *
+ *		config.scayt_contextMenuItemsOrder = 'moresuggest|control|suggest';
+ *
+ * @cfg {String} [scayt_contextMenuItemsOrder='suggest|moresuggest|control']
+ * @member CKEDITOR.config
+ */
+
+/**
+ * If set to `true`, it overrides the {@link CKEDITOR.editor#checkDirty checkDirty} functionality of CKEditor
+ * to fix SCAYT issues with incorrect `checkDirty` behavior. If set to `false`,
+ * it provides better performance on big preloaded text.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		config.scayt_handleCheckDirty = 'false';
+ *
+ * @cfg {String} [scayt_handleCheckDirty='true']
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Configures undo/redo behavior of SCAYT in CKEditor.
+ * If set to `true`, it overrides the undo/redo functionality of CKEditor
+ * to fix SCAYT issues with incorrect undo/redo behavior. If set to `false`,
+ * it provides better performance on text undo/redo.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		config.scayt_handleUndoRedo = 'false';
+ *
+ * @cfg {String} [scayt_handleUndoRedo='true']
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Enables the "Ignore All-Caps Words" option by default.
+ * You may need to {@link CKEDITOR.config#scayt_disableOptionsStorage disable option storing} for this setting to be
+ * effective because option storage has a higher priority.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		config.scayt_ignoreAllCapsWords = true;
+ *
+ * @since 4.5.6
+ * @cfg {Boolean} [scayt_ignoreAllCapsWords=false]
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Enables the "Ignore Domain Names" option by default.
+ * You may need to {@link CKEDITOR.config#scayt_disableOptionsStorage disable option storing} for this setting to be
+ * effective because option storage has a higher priority.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		config.scayt_ignoreDomainNames = true;
+ *
+ * @since 4.5.6
+ * @cfg {Boolean} [scayt_ignoreDomainNames=false]
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Enables the "Ignore Words with Mixed Case" option by default.
+ * You may need to {@link CKEDITOR.config#scayt_disableOptionsStorage disable option storing} for this setting to be
+ * effective because option storage has a higher priority.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		config.scayt_ignoreWordsWithMixedCases = true;
+ *
+ * @since 4.5.6
+ * @cfg {Boolean} [scayt_ignoreWordsWithMixedCases=false]
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Enables the "Ignore Words with Numbers" option by default.
+ * You may need to {@link CKEDITOR.config#scayt_disableOptionsStorage disable option storing} for this setting to be
+ * effective because option storage has a higher priority.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		config.scayt_ignoreWordsWithNumbers = true;
+ *
+ * @since 4.5.6
+ * @cfg {Boolean} [scayt_ignoreWordsWithNumbers=false]
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Disables storing of SCAYT options between sessions. Option storing will be turned off after a page refresh.
+ * The following settings can be used:
+ *
+ * * `'options'` &ndash; Disables storing of all SCAYT Ignore options.
+ * * `'ignore-all-caps-words'` &ndash; Disables storing of the "Ignore All-Caps Words" option.
+ * * `'ignore-domain-names'` &ndash; Disables storing of the "Ignore Domain Names" option.
+ * * `'ignore-words-with-mixed-cases'` &ndash; Disables storing of the "Ignore Words with Mixed Case" option.
+ * * `'ignore-words-with-numbers'` &ndash; Disables storing of the "Ignore Words with Numbers" option.
+ * * `'lang'` &ndash; Disables storing of the SCAYT spell check language.
+ * * `'all'` &ndash; Disables storing of all SCAYT options.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ * Example:
+ *
+ *		// Disabling one option.
+ *		config.scayt_disableOptionsStorage = 'all';
+ *
+ *		// Disabling several options.
+ *  	config.scayt_disableOptionsStorage = ['lang', 'ignore-domain-names', 'ignore-words-with-numbers'];
+ *
+ *
+ * @cfg {String|Array} [scayt_disableOptionsStorage = '']
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Specifies the names of tags that will be skipped while spell checking. This is a string containing tag names
+ * separated by commas (`','`). Please note that the `'style'` tag would be added to specified tags list.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		config.scayt_elementsToIgnore = 'del,pre';
+ *
+ * @cfg {String} [scayt_elementsToIgnore='style']
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Enables multi-language support in SCAYT. If set to `true`, turns on SCAYT multi-language support after loading the editor.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ *		config.scayt_multiLanguageMode = true;
+ *
+ * @cfg {Boolean} [scayt_multiLanguageMode=false]
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Defines additional styles for misspellings for specified languages. Styles will be applied only if
+ * the {@link CKEDITOR.config#scayt_multiLanguageMode} option is set to `true` and the [Language](http://ckeditor.com/addon/language) 
+ * plugin is included and loaded in the editor. By default, all misspellings will still be underlined with the red waveline.
+ *
+ * Read more in the [documentation](#!/guide/dev_spellcheck) and see the [SDK sample](http://sdk.ckeditor.com/samples/spellchecker.html).
+ *
+ * Example:
+ *
+ *		// Display misspellings in French language with green color and underlined with red waveline.
+ *		config.scayt_multiLanguageStyles = {
+ *			'fr': 'color: green'
+ *		};
+ *
+ *		// Display misspellings in Italian language with green color and underlined with red waveline
+ *		// and German misspellings with red color only.
+ *		config.scayt_multiLanguageStyles = {
+ *			'it': 'color: green',
+ *			'de': 'background-image: none; color: red'
+ *		};
+ *
+ * @cfg {Object} [scayt_multiLanguageStyles = {}]
+ * @member CKEDITOR.config
+ */

+ 38 - 166
app/Resources/public/css/chat.css

@@ -1,13 +1,5 @@
-body{
-	font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
-	font-size: 13px;
-  	line-height: 18px;
-  	color: #333333;
-  	margin: 0;
-  	padding: 0;
-}
 .page-chat{
-	padding: 10px;
+	padding: 10px 0;
 	background:#ffffff;
 }
 .message-form-chat .nav{
@@ -16,48 +8,7 @@ body{
 .message-form-chat .nav-tabs .active a{
   background-color: #f6f6f6;
 }
-#clear-chat{
-	width:140px;
-    padding: 13px;
-    font-size: 14px;
-    float:right;
-}
-#clear-chat img{
-	width: 20px;
-	float: left;
-	margin-right: 5px;
-}
-#clear-chat a{
-	text-decoration: none;
 
-}
-#clear-chat a:hover{
-	opacity: 0.7;
-}
-#content-chat{
-	background:#ffffff;
-	padding: 30px;
-	-webkit-border-radius: 10px;
-	-moz-border-radius: 10px;
-	border-radius: 10px;
-}
-
-textarea {
-	width: 52%;
-	padding: 3%;
-	height: 100px;
-	float: left;
-	border: 0;
-	background-color: #ffffff;
-
-	font-family: Helvetica, arial, sans-serif;
-	-webkit-border-radius: 10px;
-	-moz-border-radius: 10px;
-	border-radius: 10px;
-	border: 1px solid #EEEEEE;
-	color: #666;
-	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35) inset;
-}
 .message-student .chat-image, .message-teacher .chat-image{
  	width: 80px;
  	height: auto;
@@ -85,7 +36,7 @@ textarea {
 	font-size: 13px;
 	padding: 15px;
 	vertical-align: top;
-	width: 310px;
+	width: calc(100% - 100px);
 }
 .message-teacher .icon-message{
 	display: inline-block;
@@ -121,7 +72,7 @@ textarea {
 	font-size: 13px;
 	padding: 15px;
 	vertical-align: top;
-	width: 360px;
+	width: calc(100% - 100px);
 }
 .message-teacher .message-date{
 	color: #666;
@@ -138,121 +89,30 @@ textarea {
 	text-align: right;
 	margin-top: 10px;
 }
-.user-online .profile{
-	list-style: none;
-	padding: 0;
-	margin:0;
-}
-.chat-message-block-name {
-    font-style: italic;
-    color: #666;
-}
-.user-online .profile li{
-	margin-bottom: 5px;
-}
-.user-online .profile li a{
-	color: #0088AA;
-	text-decoration: none;
-}
-.user-online .title{
-	background: url(chat.png) no-repeat 0 center;
-	color: #0088AA;
-	padding-top: 5px;
-	padding-left: 30px;
-	font-weight: bold;
-	font-size: 16px;
-	margin-bottom: 15px;
-	width: 90%;
-}
-.delete-chat{
-	background: #F8F8F8;
-	padding-bottom: 15px;
-}
-.list-group {
-  margin-bottom: 20px;
-  padding-left: 0;
-}
-.list-group-item {
-  position: relative;
-  display: block;
-  padding-top: 5px;
-  padding-bottom: 10px;
-  padding-left: 10px;
-  padding-right: 10px;
-  margin-bottom: -1px;
-  background-color: #EEEEEE;
-  border: 1px solid #E2E2E2;
-  -webkit-border-radius: 10px;
+
+.chat-user {
+	background-color: #EEEEEE;
+	border: 1px solid #E2E2E2;
+	-webkit-border-radius: 10px;
 	-moz-border-radius: 10px;
 	border-radius: 10px;
 	color: #666;
+	margin-bottom: -1px;
+	padding: 10px;
 }
-.user-connected{
-  border-right: 1px dashed #cccccc;
-  margin-right: 5px;
-}
-li.list-group-item:hover, li.list-group-item:focus {
-  text-decoration: none;
-  background-color: #E2E2E2;
-  cursor: pointer;
-  border: 1px solid #EEEEEE;
-}
-li.list-group-item:hover a{
-	color: #000;
-}
-.user-image-chat{
-	width: 40px;
- 	height: auto;
- 	max-height: 40px;
- 	display: inline-block;
- 	vertical-align: top;
- 	-webkit-border-radius: 10px;
+.chat-user .user-image-chat {
+	-webkit-border-radius: 10px;
 	-moz-border-radius: 10px;
+	border: 2px solid #FFF;
 	border-radius: 10px;
-	border:2px solid #ffffff;
+	display: inline-block;
+	height: auto;
+	margin-right: 10px;
+	max-height: 40px;
 	float: left;
-	margin-right: 5px;
-}
-.noSelect {
-    user-select: none;
-    -o-user-select: none;
-    -moz-user-select: none;
-    -khtml-user-select: none;
-    -webkit-user-select: none;
-}
-.btn-send {
-	background: #87e0fd; /* Old browsers */
-	background: -moz-linear-gradient(top, #87e0fd 0%, #53cbf1 40%, #05abe0 100%); /* FF3.6+ */
-	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#87e0fd), color-stop(40%,#53cbf1), color-stop(100%,#05abe0)); /* Chrome,Safari4+ */
-	background: -webkit-linear-gradient(top, #87e0fd 0%,#53cbf1 40%,#05abe0 100%); /* Chrome10+,Safari5.1+ */
-	background: -o-linear-gradient(top, #87e0fd 0%,#53cbf1 40%,#05abe0 100%); /* Opera 11.10+ */
-	background: -ms-linear-gradient(top, #87e0fd 0%,#53cbf1 40%,#05abe0 100%); /* IE10+ */
-	background: linear-gradient(to bottom, #87e0fd 0%,#53cbf1 40%,#05abe0 100%); /* W3C */
-	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#87e0fd', endColorstr='#05abe0',GradientType=0 ); /* IE6-9 */
-	-webkit-border-radius: 15px;
-	-moz-border-radius: 15px;
-	border-radius: 15px;
-	border:1px solid #53cbf1;
-	display:inline-block;
-	color:#ffffff;
-	font-family:Arial;
-	font-size:22px;
-	font-weight:bold;
-	font-style:normal;
-	height:80px;
-	line-height:80px;
-	width:131px;
-	text-decoration:none;
-	text-align:center;
-	cursor: pointer;
-}
-.btn-send:hover {
-	opacity: 0.8;
-}
-.btn-send:active {
-	position:relative;
-	top:1px;
+	width: 40px;
 }
+
 .emoticons-chat img{
   	width: 24px;
   	border: none;
@@ -267,21 +127,17 @@ li.list-group-item:hover a{
 }
 
 .emoji-menu {
-    margin-left: 0px;
-    width:468px;
-    left: 11px !important;
+	margin-left: -234px;
+	margin-top: -224px;
+	width: 468px;
 }
 
 .emoji-wysiwyg-editor-preview,
 .emoji-wysiwyg-editor {
-    width: 454px;
     padding: 3%;
     height: 50px;
-    float: left;
     border: 0;
     background-color: #ffffff;
-
-    font-family: Helvetica, arial, sans-serif;
     -webkit-border-radius: 10px;
     -moz-border-radius: 10px;
     border-radius: 10px;
@@ -289,3 +145,19 @@ li.list-group-item:hover a{
     color: #666;
     box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35) inset;
 }
+
+#chat-tabs .tab-content{
+	margin-top: 15px;
+}
+
+.chat-history {
+	height: 400px;
+	overflow: auto;
+}
+
+#chat-users {
+	margin-left: 0;
+}
+#chat-users div.chat-user > div {
+	padding: 5px;
+}

+ 0 - 1
app/config/mail.conf.dist.php

@@ -1,5 +1,4 @@
 <?php
-
 /**
  *	This file holds the configuration settings
  *	for phpmailer Class.

+ 4 - 1
documentation/installation_guide.html

@@ -328,6 +328,7 @@ Please note that if you (unluckily) upgraded from any of the 1.9 versions to 1.1
 
 <h3>3.2 Upgrading from Chamilo 1.9.x</h3>
 <ul>
+  <li> make sure you don't have tables from previous versions of Chamilo still hanging around. These can cause the upgrade to fail. In particular, tables from versions 1.8.* could have multiple tables for each course, resulting in many tables with the same prefix. Only tables without prefix or with a "c_" prefix exist in 1.9 and superior versions. Make sure none of these tables persist. Take a backup of your database (just in case) and delete these prefixed tables (drop table ...).</li>
   <li> check that you haven't left any customised stylesheet or image <span class="text-muted">(if you have, make sure you keep a copy on the side*)</span></li>
   <li> download the Chamilo 1.10 install package from the <a href="http://www.chamilo.org/download">Chamilo download page</a></li>
   <li> unzip the new files of Chamilo 1.10 over the files of the older version (or unzip the files in one folder and then copy the files from there to the older version's directory)</li>
@@ -335,6 +336,7 @@ Please note that if you (unluckily) upgraded from any of the 1.9 versions to 1.1
   <li> make sure "AllowOverride All" is present in your Apache configuration, as interpreting the .htaccess files is very important for Chamilo to work (note that the Order-Allow directive has been replaced by "Require all granted" in Apache 2.4)</li>
   <li> point your browser on your portal URL + main/install/</li>
   <li> click&nbsp;<span style="font-style: italic;">Install</span>, then choose <span style="font-style: italic;">Upgrade from 1.9.*</span></li>
+  <li> once your portal is upgraded, clean your app/cache/twig directory: delete all the contents *in* this directory (do NOT remove the directory itself, only its contents!). It will all be re-generated. You can also delete the contents of this directory through the "Archive directory cleanup" option in the "System" box of the Administration page.</li>
 </ul>
 
 <br />
@@ -360,7 +362,8 @@ Do not delete the previous Chamilo installation directory before installing
 the new one. The upgrade process should take care of all unrequired folders.</p>
 
     <h3>3.2 Upgrading from Chamilo 1.8.x</h3>
-    To upgrade from version of Chamilo prior to 1.9.0, you will need to first upgrade them to 1.9.10.2, then upgrade again (separately) to 1.10.x
+    To upgrade from version of Chamilo prior to 1.9.0, you will need to first upgrade them to 1.9.10.x, then upgrade again (separately) to 1.10.x.
+    You can find the 1.9.10.x packages here: <a href="https://github.com/chamilo/chamilo-lms/releases">https://github.com/chamilo/chamilo-lms/releases</a>
 
     <p></p>
 <h3>3.5 In both last cases</h3>

+ 7 - 6
documentation/installation_guide_es_ES.html

@@ -295,13 +295,14 @@ Dado que se trata sólo de un cambio de versión menor  previa de Chamilo 1.10.*
 
 <h3>3.2 Actualizar desde Chamilo 1.9.x</h3>
 <ul>
+  <li>Asegúrese que ninguna tabla de una versión anterior (a la 1.9) exista en su base de datos. Estas tablas pueden causar errores durante el proceso de actualización hacia versiones superiores. En particular, las tablas de versiones 1.8.* y anteriores podían repetirse una vez por curso, resultando en una gran cantidad de tablas que compartían el mismo prefijo. Solo las tablas sin prefijo o con un prefijo "c_" son legítimas en Chamilo 1.9 y siguientes. Asegúrese de que ninguna de estas antiguas tablas persista. Tóme una copia de seguridad de la base de datos (por si a caso) y luego borre estas tablas con prefijo (drop table ...).</li>
   <li>Compruebe que no ha dejado ninguna hoja de estilo o imagen personalizada (si la tuviera, asegúrese de realizar una copia de respaldo*)</li>
   <li>Descargue el paquete de instalación de Chamilo 1.9 desde la página de descarga de Chamilo</li>
   <li>Descomprima los nuevos ficheros de Chamilo 1.9 sobre los ficheros de la antigua versión ( o descomprima en una carpeta y luego copie los archivos en el directorio de la versión antigua)</li>
-    <li>Asegúrese *por completo* que el archivo .htaccess de la versión 1.10 ha sido copiado en la raíz también</li>
-    <li>Asegúrese que "AllowOverride All" está presente en su configuración de Apache, ya que interpretar el archivo .htaccess es muy importante para que Chamilo funcione (ojo que la directiva Order-Allow ha sido remplazada por "Require all granted" en Apache 2.4)</li>
-    <li>Escriba en su navegador web la URL de su portal + main/install/</li>
-    <li>Elija su idioma y haga click sobre Actualizar desde 1.9.x</li>
+  <li>Asegúrese *por completo* que el archivo .htaccess de la versión 1.10 ha sido copiado en la raíz también</li>
+  <li>Asegúrese que "AllowOverride All" está presente en su configuración de Apache, ya que interpretar el archivo .htaccess es muy importante para que Chamilo funcione (ojo que la directiva Order-Allow ha sido remplazada por "Require all granted" en Apache 2.4)</li>
+  <li>Escriba en su navegador web la URL de su portal + main/install/</li>
+  <li>Elija su idioma y haga click sobre Actualizar desde 1.9.x</li>
 </ul>
 <p>
     * Los estilos e imágenes están ubicados en el directorio main/css o main/img.
@@ -319,8 +320,8 @@ Dado que se trata sólo de un cambio de versión menor  previa de Chamilo 1.10.*
 <br />
 
 <h3>3.3 Actualizar desde Chamilo o Dok€os 1.8.x</h3>
-Para actualizar desde una versión previa a la 1.9.0, deberá a partir de ahora primero actualizar a la versión 1.9.10.2, para luego actualizar de ahí a la 1.10.x.
-
+Para actualizar desde una versión previa a la 1.9.0, deberá a partir de ahora primero actualizar a la versión 1.9.10.x, para luego actualizar de ahí a la 1.10.x.
+Podrá encontrar una versión descargable de 1.9.10.x aquí: <a href="https://github.com/chamilo/chamilo-lms/releases">https://github.com/chamilo/chamilo-lms/releases</a>
 
 <h3>3.4 En ambos últimos casos</h3>
 

+ 4 - 2
documentation/installation_guide_fr_FR.html

@@ -386,6 +386,7 @@
 
             <h3>3.2 Mettre à jour depuis Chamilo 1.9.x</h3>
             <ul>
+                <li> assurez-vous qu'aucune table ne persiste d'une version antérieure de Chamilo. Ces tables peuvent en effet causer une erreur durant la mise à jour. En particulier, les tables des versions 1.8.* et antérieures pouvaient se répéter une fois par cours, résultant en un grand nombre de tables partageant le même préfixe. Seules les tables sans préfixe ou avec un préfixe "c_" sont légitimes dans les versions 1.9 et supérieures. Assurez-vous qu'aucune de ces anciennes tables ne persiste. Prenez une copie de sauvegarde de votre base de données (au cas où) puis supprimez-les (drop table ...).</li>
                 <li> vérifiez que vous n'avez pas laissé de feuille de style personnalisée ou d'image <span class="text-muted">(le cas échant, faites-en une sauvegarde*)</span></li>
                 <li> télécharger le paquet Chamilo 1.10 depuis la <a href="http://www.chamilo.org/download">page de téléchargement de Chamilo</a></li>
                 <li> décompressez les nouveaux fichiers de Chamilo 1.10 sur les fichiers de votre ancienne installation (ou décompressez les dans un nouveau dossier et copier les fichiers extraits sur les anciens fichiers).</li>
@@ -420,8 +421,9 @@
             </p>
 
             <h3>3.3 Mettre à jour depuis Chamilo 1.8.x</h3>
-            Pour mettre à jour depuis une version antérieure à la 1.9.0, vous devrez commencer par la mettre à jour vers la version 1.9.10.2,
-            et seulement alors mettre à jours vers la 1.10.x
+            Pour mettre à jour depuis une version antérieure à la 1.9.0, vous devrez commencer par la mettre à jour vers la version 1.9.10.x,
+            et seulement alors mettre à jours vers la 1.10.x.
+            Vous pouvez trouver une version téléchargeable de 1.9.10.x ici: <a href="https://github.com/chamilo/chamilo-lms/releases">https://github.com/chamilo/chamilo-lms/releases</a>
             <p></p>
             <h3>3.4 Dans les deux derniers cas</h3>
 

+ 11 - 8
documentation/optimization.html

@@ -342,7 +342,7 @@ ALTER TABLE user_rel_tag ADD INDEX idx_user_rel_tag_user (user_id);
 In Chamilo 1.10.0 (the first version of the serie), many indexes were forgotten, so you can boost your database by adding the following indexes:<br />
 <pre>
 alter table extra_field_values add index idx_extra_field_values (field_id, item_id);
-alter table usergroup_rel_user add index idx_usergroup_ru (group_id);
+alter table usergroup_rel_user add index idx_usergroup_ru (usergroup_id);
 alter table usergroup_rel_user add index idx_usergroup_ru_u (user_id);
 alter table c_student_publication add index idxstudpub_cid (c_id);
 alter table c_student_publication add index idxstudpub_uid (user_id);
@@ -351,10 +351,13 @@ alter table c_quiz_rel_question ADD INDEX idx_cqrq_qid (question_id);
 alter table c_quiz_rel_question ADD INDEX idx_cqrq_cid (c_id);
 alter table c_quiz_answer add index idx_qa_cidqid (c_id, question_id);
 </pre>
+In Chamilo 1.10.6, an additional query was confirmed to still have effect a considerable effect:
+<pre>
+alter table c_quiz_question_rel_category add index idx_qqrc_qid (question_id);
+</pre>
 <hr />
 <h2><a name="3.Indexes-caching"></a>3. Indexes caching</h2>
 One good reference: <a href="http://dev.mysql.com/doc/refman/5.1/en/multiple-key-caches.html">MySQL documentation on multiple key caches</a><br />
-
 <hr />
 
 <h2><a name="4.Sessions-directories"></a>4. Sessions directories</h2>
@@ -555,23 +558,23 @@ This is easy, doesn't require a server reload and you should see the results pre
     you should avoid using this technique.
 </p>
 <p>
-You can also mitigate the risk by disabling permissions check only 
+You can also mitigate the risk by disabling permissions check only
 for some static resource like css,js and fonts files.
 <br/>
-For that is required to load header module  
+For that is required to load header module
 in apache (check with a2enmod in your favorite root terminal)<br />
 add theses line after RewriteBase /courses/:
 <pre>
 &lt;IfModule mod_headers.c&gt;
     # all file name ended with these  extensions names will bypass the permission check   (and also served by the browser cache at  the next request)
     &lt;FilesMatch &quot;\.(gif|jpg|jpeg|png|js|pdf|ico|icon|css|swf|avi|mp3|ogg|wav|ttf|otf|eot|woff)$&quot;&gt;
-        Header unset Cache-Control  
-        Header set Cache-Control &quot;public, max-age=29030400&quot; 
-        RequestHeader unset Cookie      
+        Header unset Cache-Control
+        Header set Cache-Control &quot;public, max-age=29030400&quot;
+        RequestHeader unset Cookie
         Header unset ETag
     &lt;/FilesMatch&gt;
 &lt;/IfModule&gt;
-# also adjust files here 
+# also adjust files here
 RewriteRule (\.(html|gif|jpg|jpeg|png|js|pdf|ico|icon|css|swf|avi|mp3|ogg|wav|ttf|otf|eot|woff))$ - [L]
 </pre>
 </p>

+ 0 - 1
index.php

@@ -15,7 +15,6 @@ define('CHAMILO_LOAD_WYSIWYG', false);
 $cidReset = true;
 
 require_once 'main/inc/global.inc.php';
-require_once 'main/chat/chat_functions.lib.php';
 //require_once 'main/auth/external_login/facebook.inc.php';
 
 // The section (for the tabs).

+ 1 - 1
main/admin/add_users_to_usergroup.php

@@ -177,7 +177,7 @@ if ($use_extra_fields) {
     if (count($extra_field_result)>1) {
         for ($i=0; $i<count($extra_field_result)-1; $i++) {
             if (is_array($extra_field_result[$i+1])) {
-                $final_result  = array_intersect($extra_field_result[$i], $extra_field_result[$i+1]);
+                $final_result = array_intersect($extra_field_result[$i], $extra_field_result[$i+1]);
             }
         }
     } else {

+ 31 - 3
main/admin/index.php

@@ -78,7 +78,7 @@ if (!empty($hook)) {
 }
 
 /* Users */
-$blocks['users']['icon'] = Display::return_icon('members.gif', get_lang('Users'), array(), ICON_SIZE_MEDIUM, false);
+$blocks['users']['icon'] = Display::return_icon('members.png', get_lang('Users'), array(), ICON_SIZE_MEDIUM, false);
 $blocks['users']['label'] = api_ucfirst(get_lang('Users'));
 $blocks['users']['class'] = 'block-admin-users';
 
@@ -394,9 +394,37 @@ if (api_is_platform_admin()) {
         $blocks['skills']['search_form'] = null;
     }
 
+    /* Plugins */
+    global $_plugins;
+    if (isset($_plugins['menu_administrator']) && count($_plugins['menu_administrator']) > 0) {
+        $blocks['plugins']['icon'] = Display::return_icon(
+            'plugins.png',
+             get_lang('Plugins'),
+             array(),
+             ICON_SIZE_MEDIUM,
+             false
+        );
+        $blocks['plugins']['label'] = api_ucfirst(get_lang('Plugins'));
+        $blocks['plugins']['class'] = 'block-admin-platform';
+        $blocks['plugins']['editable'] = true;
+
+        $plugin_obj = new AppPlugin();
+        $items = array();
+        foreach ($_plugins['menu_administrator'] as $plugin_name) {
+            $plugin_info = $plugin_obj->getPluginInfo($plugin_name);
+            $items[] = array(
+                'url' => api_get_path(WEB_CODE_PATH) . '../plugin/'.$plugin_name.'/start.php',
+                'label' => $plugin_info['title']
+            );
+        }
+
+        $blocks['plugins']['items'] = $items;
+        $blocks['plugins']['extra'] = null;
+    }
+
     /* Chamilo.org */
 
-    $blocks['chamilo']['icon'] = Display::return_icon('logo.png', 'Chamilo.org', array(), ICON_SIZE_MEDIUM, false);
+    $blocks['chamilo']['icon'] = Display::return_icon('platform.png', 'Chamilo.org', array(), ICON_SIZE_MEDIUM, false);
     $blocks['chamilo']['label'] = 'Chamilo.org';
     $blocks['chamilo']['class'] = 'block-admin-chamilo';
 
@@ -420,7 +448,7 @@ if (api_is_platform_admin()) {
     $blocks['chamilo']['search_form'] = null;
 
     // Version check
-    $blocks['version_check']['icon'] = Display::return_icon('logo.png', 'Chamilo.org', array(), ICON_SIZE_MEDIUM, false);
+    $blocks['version_check']['icon'] = Display::return_icon('platform.png', 'Chamilo.org', array(), ICON_SIZE_MEDIUM, false);
     $blocks['version_check']['label'] = get_lang('VersionCheck');
     $blocks['version_check']['extra'] = '<div class="admin-block-version"></div>';
     $blocks['version_check']['search_form'] = null;

+ 40 - 46
main/admin/subscribe_user2course.php

@@ -11,7 +11,6 @@
 * 	@todo use formvalidator for the form
 */
 
-/* INIT SECTION */
 $cidReset = true;
 require_once '../inc/global.inc.php';
 $this_section = SECTION_PLATFORM_ADMIN;
@@ -23,28 +22,28 @@ api_protect_admin_script();
 $form_sent = 0;
 $first_letter_user = '';
 $first_letter_course = '';
-$courses = array ();
+$courses = array();
 $users = array();
 
 $tbl_course = Database :: get_main_table(TABLE_MAIN_COURSE);
-$tbl_user 	= Database :: get_main_table(TABLE_MAIN_USER);
+$tbl_user = Database :: get_main_table(TABLE_MAIN_USER);
 
 /* Header */
 $tool_name = get_lang('AddUsersToACourse');
 $interbreadcrumb[] = array ("url" => 'index.php', "name" => get_lang('PlatformAdmin'));
 
-$htmlHeadXtra[] = '
-<script type="text/javascript">
+$htmlHeadXtra[] = '<script>
 function validate_filter() {
-        document.formulaire.form_sent.value=0;
-        document.formulaire.submit();
+    document.formulaire.form_sent.value=0;
+    document.formulaire.submit();
 }
 </script>';
 
 // displaying the header
 Display :: display_header($tool_name);
 
-$link_add_group = '<a href="usergroups.php">'.Display::return_icon('multiple.gif',get_lang('RegistrationByUsersGroups')).get_lang('RegistrationByUsersGroups').'</a>';
+$link_add_group = '<a href="usergroups.php">'.
+    Display::return_icon('multiple.gif', get_lang('RegistrationByUsersGroups')).get_lang('RegistrationByUsersGroups').'</a>';
 echo '<div class="actions">'.$link_add_group.'</div>';
 
 $form = new FormValidator('subscribe_user2course');
@@ -52,13 +51,18 @@ $form->addElement('header', '', $tool_name);
 $form->display();
 
 //checking for extra field with filter on
-$extra_field_list= UserManager::get_extra_fields();
+$extra_field_list = UserManager::get_extra_fields();
+
 $new_field_list = array();
 if (is_array($extra_field_list)) {
     foreach ($extra_field_list as $extra_field) {
         //if is enabled to filter and is a "<select>" field type
-        if ($extra_field[8]==1 && $extra_field[2]==4 ) {
-            $new_field_list[] = array('name'=> $extra_field[3], 'variable'=>$extra_field[1], 'data'=> $extra_field[9]);
+        if ($extra_field[8] == 1 && $extra_field[2] == ExtraField::FIELD_TYPE_SELECT) {
+            $new_field_list[] = array(
+                'name' => $extra_field[3],
+                'variable' => $extra_field[1],
+                'data' => $extra_field[9],
+            );
         }
     }
 }
@@ -66,8 +70,8 @@ if (is_array($extra_field_list)) {
 /* React on POSTed request */
 if (isset($_POST['form_sent']) && $_POST['form_sent']) {
     $form_sent = $_POST['form_sent'];
-    $users = isset($_POST['UserList']) && is_array($_POST['UserList']) ? $_POST['UserList'] : array() ;
-    $courses = isset($_POST['CourseList']) && is_array($_POST['CourseList']) ? $_POST['CourseList'] : array() ;
+    $users = isset($_POST['UserList']) && is_array($_POST['UserList']) ? $_POST['UserList'] : array();
+    $courses = isset($_POST['CourseList']) && is_array($_POST['CourseList']) ? $_POST['CourseList'] : array();
     $first_letter_user = $_POST['firstLetterUser'];
     $first_letter_course = $_POST['firstLetterCourse'];
 
@@ -105,7 +109,7 @@ if (empty($first_letter_user)) {
     $sql = "SELECT count(*) as nb_users FROM $tbl_user";
     $result = Database::query($sql);
     $num_row = Database::fetch_array($result);
-    if  ($num_row['nb_users']>1000) {
+    if ($num_row['nb_users'] > 1000) {
         //if there are too much users to gracefully handle with the HTML select list,
         // assign a default filter on users names
         $first_letter_user = 'A';
@@ -113,18 +117,17 @@ if (empty($first_letter_user)) {
     unset($result);
 }
 
-
 $where_filter = null;
 
 //Filter by Extra Fields
 $use_extra_fields = false;
 if (is_array($extra_field_list)) {
-    if (is_array($new_field_list) && count($new_field_list)>0 ) {
-        $result_list=array();
+    if (is_array($new_field_list) && count($new_field_list) > 0) {
+        $result_list = array();
         foreach ($new_field_list as $new_field) {
             $varname = 'field_'.$new_field['variable'];
             if (UserManager::is_extra_field_available($new_field['variable'])) {
-                if (isset($_POST[$varname]) && $_POST[$varname]!='0') {
+                if (isset($_POST[$varname]) && $_POST[$varname] != '0') {
                     $use_extra_fields = true;
                     $extra_field_result[]= UserManager::get_extra_user_data_by_value(
                         $new_field['variable'],
@@ -136,12 +139,13 @@ if (is_array($extra_field_list)) {
     }
 }
 
+
 if ($use_extra_fields) {
     $final_result = array();
-    if (count($extra_field_result)>1) {
-        for($i=0;$i<count($extra_field_result)-1;$i++) {
+    if (count($extra_field_result) > 1) {
+        for ($i = 0; $i < count($extra_field_result) - 1; $i++) {
             if (is_array($extra_field_result[$i+1])) {
-                $final_result  = array_intersect($extra_field_result[$i],$extra_field_result[$i+1]);
+                $final_result  = array_intersect($extra_field_result[$i], $extra_field_result[$i+1]);
             }
         }
     } else {
@@ -157,7 +161,7 @@ if ($use_extra_fields) {
         }
     } else {
         if (is_array($final_result) && count($final_result)>0) {
-            $where_filter = " AND user_id IN  ('".implode("','",$final_result)."') ";
+            $where_filter = " AND user_id IN  ('".implode("','", $final_result)."') ";
         } else {
             //no results
             $where_filter = " AND user_id  = -1";
@@ -182,9 +186,9 @@ $sql = "SELECT user_id, lastname, firstname, username, official_code
 if (api_is_multiple_url_enabled()) {
     $tbl_user_rel_access_url= Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
     $access_url_id = api_get_current_access_url_id();
-    if ($access_url_id != -1){
+    if ($access_url_id != -1) {
         $sql = "SELECT u.user_id,lastname,firstname,username, official_code
-                FROM ".$tbl_user ." u
+                FROM $tbl_user u
                 INNER JOIN $tbl_user_rel_access_url user_rel_url
                 ON (user_rel_url.user_id = u.user_id)
                 WHERE
@@ -208,7 +212,7 @@ $sql = "SELECT code,visual_code,title
 if (api_is_multiple_url_enabled()) {
     $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
     $access_url_id = api_get_current_access_url_id();
-    if ($access_url_id != -1){
+    if ($access_url_id != -1) {
         $sql = "SELECT code, visual_code, title
                 FROM $tbl_course as course
                 INNER JOIN $tbl_course_rel_access_url course_rel_url
@@ -228,7 +232,7 @@ unset($result);
 <form name="formulaire" method="post" action="<?php echo api_get_self(); ?>" style="margin:0px;">
 <?php
 if (is_array($extra_field_list)) {
-    if (is_array($new_field_list) && count($new_field_list)>0 ) {
+    if (is_array($new_field_list) && count($new_field_list) > 0) {
         echo '<h3>'.get_lang('FilterUsers').'</h3>';
         foreach ($new_field_list as $new_field) {
             echo $new_field['name'];
@@ -238,7 +242,7 @@ if (is_array($extra_field_list)) {
             foreach	($new_field['data'] as $option) {
                 $checked='';
                 if (isset($_POST[$varname])) {
-                    if ($_POST[$varname]==$option[1]) {
+                    if ($_POST[$varname] == $option[1]) {
                         $checked = 'selected="true"';
                     }
                 }
@@ -282,24 +286,18 @@ if (is_array($extra_field_list)) {
    <tr>
     <td width="40%" align="center">
      <select name="UserList[]" multiple="multiple" size="20" style="width:300px;">
-<?php
-    foreach ($db_users as $user) {
-?>
-      <option value="<?php echo $user['user_id']; ?>" <?php if(in_array($user['user_id'],$users)) echo 'selected="selected"'; ?>>
+    <?php foreach ($db_users as $user) { ?>
+          <option value="<?php echo $user['user_id']; ?>" <?php if(in_array($user['user_id'],$users)) echo 'selected="selected"'; ?>>
       <?php
         $userName = api_get_person_name($user['firstname'], $user['lastname']).' ('.$user['username'].')';
         if ($showOfficialCode) {
-
             $officialCode = !empty($user['official_code']) ? $user['official_code'].' - ' : '? - ';
             $userName = $officialCode.$userName;
         }
-
         echo $userName;
       ?>
-      </option>
-<?php
-}
-?>
+          </option>
+    <?php } ?>
     </select>
    </td>
    <td width="20%" valign="middle" align="center">
@@ -309,15 +307,11 @@ if (is_array($extra_field_list)) {
    </td>
    <td width="40%" align="center">
     <select name="CourseList[]" multiple="multiple" size="20" style="width:300px;">
-<?php
-    foreach ($db_courses as $course) {
-?>
-     <option value="<?php echo $course['code']; ?>" <?php if(in_array($course['code'],$courses)) echo 'selected="selected"'; ?>>
-         <?php echo '('.$course['visual_code'].') '.$course['title']; ?>
-     </option>
-<?php
-}
-?>
+    <?php foreach ($db_courses as $course) { ?>
+         <option value="<?php echo $course['code']; ?>" <?php if(in_array($course['code'],$courses)) echo 'selected="selected"'; ?>>
+             <?php echo '('.$course['visual_code'].') '.$course['title']; ?>
+         </option>
+    <?php } ?>
     </select>
    </td>
   </tr>

+ 204 - 0
main/admin/teachers_time_by_session_report.php

@@ -0,0 +1,204 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+/**
+ * Generate a teacher time report in platform by session only
+ * @package chamilo.admin
+ */
+
+use \Chamilo\CoreBundle\Entity\Session;
+use \Doctrine\Common\Collections\Criteria;
+
+$cidReset = true;
+
+require_once '../inc/global.inc.php';
+require_once api_get_path(SYS_CODE_PATH) . 'work/work.lib.php';
+
+api_protect_admin_script();
+
+$toolName = get_lang('TeacherTimeReportBySession');
+
+$em = Database::getManager();
+$sessionsInfo = SessionManager::get_sessions_list([], ['name']);
+$session = null;
+
+$form = new FormValidator('teacher_time_report_by_session', 'GET');
+$selectSession = $form->addSelect('session', get_lang('Session'), [0 => get_lang('None')]);
+$form->addButtonFilter(get_lang('Filter'));
+
+foreach ($sessionsInfo as $sessionInfo) {
+    $selectSession->addOption($sessionInfo['name'], $sessionInfo['id']);
+}
+
+if (isset($_GET['session']) && intval($_GET['session'])) {
+    $form->setDefaults(['session' => intval($_GET['session'])]);
+
+    $session = $em->find('ChamiloCoreBundle:Session', intval($_GET['session']));
+}
+
+$data = [];
+$coursesInfo = [];
+$usersInfo = [];
+
+if ($session) {
+    $sessionCourses = $session->getCourses();
+
+    foreach ($sessionCourses as $sessionCourse) {
+        $course = $sessionCourse->getCourse();
+        $coursesInfo[$course->getId()] =  $course->getCode();
+        $criteria = Criteria::create()->where(
+            Criteria::expr()->eq("status", Session::COACH)
+        );
+        $userCourseSubscriptions = $session
+            ->getUserCourseSubscriptions()
+            ->matching($criteria);
+
+        foreach ($userCourseSubscriptions as $userCourseSubscription) {
+            $user = $userCourseSubscription->getUser();
+
+            if (!array_key_exists($user->getId(), $usersInfo)) {
+                $usersInfo[$user->getId()] = [
+                    'code' => $user->getOfficialCode(),
+                    'complete_name' => $user->getCompleteName(),
+                    'time_in_platform' => api_time_to_hms(
+                        Tracking::get_time_spent_on_the_platform($user->getId(), 'ever')
+                    ),
+                    'first_connection' => Tracking::get_first_connection_date($user->getId()),
+                    'last_connection' => Tracking::get_last_connection_date($user->getId()),
+                ];
+            }
+
+            $usersInfo[$user->getId()][$course->getId() . '_number_of_students'] = null;
+            $usersInfo[$user->getId()][$course->getId() . '_number_of_works'] = null;
+            $usersInfo[$user->getId()][$course->getId() . '_last_work'] = null;
+            $usersInfo[$user->getId()][$course->getId() . '_time_spent_of_course'] = null;
+
+            if (!$session->hasCoachInCourseWithStatus($user, $course)) {
+                continue;
+            }
+
+            $works = $em
+                ->getRepository('ChamiloCourseBundle:CStudentPublication')
+                ->findByTeacher($user, $course, $session->getId());
+
+            $usersInfo[$user->getId()][$course->getId() . '_number_of_students'] = $sessionCourse->getNbrUsers();
+            $usersInfo[$user->getId()][$course->getId() . '_number_of_works'] = count($works);
+            $usersInfo[$user->getId()][$course->getId() . '_time_spent_of_course'] = api_time_to_hms(
+                Tracking::get_time_spent_on_the_course($user->getId(), $course->getId(), $session->getId())
+            );
+
+            $lastWork = array_pop($works);
+
+            if (!$lastWork) {
+                continue;
+            }
+
+            $lastFormattedDate = api_format_date($lastWork->getSentDate()->getTimestamp(), DATE_TIME_FORMAT_SHORT);
+
+            $usersInfo[$user->getId()][$course->getId() . '_last_work'] = api_format_date(
+                $lastWork->getSentDate()->getTimestamp(),
+                DATE_TIME_FORMAT_SHORT
+            );
+        }
+    }
+}
+
+if (isset($_GET['export']) && $session && ($coursesInfo && $usersInfo)) {
+    $fileName = get_lang('TeacherTimeReport') . ' ' . api_get_local_time();
+
+    $dataToExport = [];
+    $dataToExport[] = [$toolName, $session->getName()];
+    $dataToExport['headers'] = [
+        get_lang('OfficialCode'),
+        get_lang('CoachName'),
+        get_lang('TimeSpentOnThePlatform'),
+        get_lang('FirstLoginInPlatform'),
+        get_lang('LatestLoginInPlatform'),
+    ];
+
+    foreach ($coursesInfo as $courseCode) {
+        $dataToExport['headers'][] = $courseCode;
+        $dataToExport['headers'][] = get_lang('NumberOfWorks');
+        $dataToExport['headers'][] = get_lang('LastWork');
+        $dataToExport['headers'][] = sprintf(get_lang('TimeReportForCourseX'), $courseCode);
+    }
+
+    foreach ($usersInfo as $user) {
+        $dataToExport[] = $user;
+    }
+
+    foreach ($data as $row) {
+        $contents = [
+            $row['code'],
+            $row['complete_name'],
+            $row['time_in_platform'],
+            $row['first_connection'],
+            $row['last_connection']
+        ];
+
+        foreach ($row['courses'] as $course) {
+            $headers[] = $course['code'];
+            $headers[] = get_lang('NumberOfWorks');
+            $headers[] = get_lang('LastWork');
+            $headers[] = sprintf(get_lang('TimeReportForCourseX'), $course['code']);
+            $contents[] = $course['number_of_students'];
+            $contents[] = $course['number_of_works'];
+            $contents[] = $course['last_work'];
+            $contents[] = $course['time_spent_of_course'];
+        }
+
+        $dataToExport[] = [get_lang('Session'), $session->getName()];
+
+        $dataToExport[] = $headers;
+        $dataToExport[] = $contents;
+    }
+
+    switch ($_GET['export']) {
+        case 'xls':
+            Export::export_table_xls_html($dataToExport, $fileName);
+            break;
+        case 'csv':
+            Export::arrayToCsv($dataToExport, $fileName);
+            break;
+    }
+    exit;
+}
+
+$this_section = SECTION_PLATFORM_ADMIN;
+$interbreadcrumb[] = ['url' => 'index.php', 'name' => get_lang('Administration')];
+$interbreadcrumb[] = [
+    'url' => api_get_path(WEB_CODE_PATH) . 'admin/teacher_time_report.php',
+    'name' => get_lang('TeacherTimeReport')
+];
+
+$actions = [];
+
+if ($session) {
+    $actions = [
+        Display::url(
+            Display::return_icon('export_csv.png', get_lang('ExportAsCSV'), [], ICON_SIZE_MEDIUM),
+            api_get_self() . '?' . http_build_query(['export' => 'csv', 'session' => $session->getId()])
+        ),
+        Display::url(
+            Display::return_icon('export_excel.png', get_lang('ExportAsXLS'), [], ICON_SIZE_MEDIUM),
+            api_get_self() . '?' . http_build_query(['export' => 'xls', 'session' => $session->getId()])
+        )
+    ];
+}
+
+$view = new Template($toolName);
+$view->assign('form', $form->returnForm());
+
+if ($session) {
+    $view->assign('session', ['id' => $session->getId(), 'name' => $session->getName()]);
+    $view->assign('courses', $coursesInfo);
+    $view->assign('users', $usersInfo);
+}
+
+$template = $view->get_template('admin/teachers_time_by_session_report.tpl');
+$content = $view->fetch($template);
+
+$view->assign('header', $toolName);
+$view->assign('actions', implode(' ', $actions));
+$view->assign('content', $content);
+$view->display_one_col_template();

+ 1 - 1
main/auth/courses.php

@@ -62,7 +62,7 @@ if (isset($_GET['action']) && in_array($_GET['action'], $actions)) {
     $action = Security::remove_XSS($_GET['action']);
 }
 
-$categoryCode = isset($_GET['category_code']) ? $_GET['category_code'] : 'ALL';
+$categoryCode = isset($_GET['category_code']) && !empty($_GET['category_code']) ? $_GET['category_code'] : 'ALL';
 
 $nameTools = getCourseCatalogNameTools($action);
 if (empty($nameTools)) {

+ 10 - 3
main/auth/courses_controller.php

@@ -90,14 +90,20 @@ class CoursesController
      * @internal param \action $string
      * @internal param \Category $string code (optional)
      */
-    public function courses_categories($action, $category_code = null, $message = '', $error = '', $content = null, $limit = array())
-    {
+    public function courses_categories(
+        $action,
+        $category_code = null,
+        $message = '',
+        $error = '',
+        $content = null,
+        $limit = array()
+    ) {
         $data = array();
         $browse_course_categories = $this->model->browse_course_categories();
         $data['countCoursesInCategory'] = $this->model->count_courses_in_category($category_code);
         if ($action == 'display_random_courses') {
             // Random value is used instead limit filter
-            $data['browse_courses_in_category'] = $this->model->browse_courses_in_category(null, 10);
+            $data['browse_courses_in_category'] = $this->model->browse_courses_in_category(null, 12);
             $data['countCoursesInCategory'] = count($data['browse_courses_in_category']);
         } else {
             if (!isset($category_code)) {
@@ -110,6 +116,7 @@ class CoursesController
         $data['browse_course_categories'] = $browse_course_categories;
         $data['code'] = Security::remove_XSS($category_code);
 
+
         // getting all the courses to which the user is subscribed to
         $curr_user_id = api_get_user_id();
         $user_courses = $this->model->get_courses_of_user($curr_user_id);

+ 11 - 6
main/auth/external_login/newUser.ldap.php

@@ -44,26 +44,31 @@ require_once dirname(__FILE__) . '/functions.inc.php';
 
 $ldap_user = extldap_authenticate($login, $password);
 if ($ldap_user !== false) {
+    $em = Database::getManager();
     $chamilo_user = extldap_get_chamilo_user($ldap_user);
     //username is not on the ldap, we have to use $login variable
     $chamilo_user['username'] = $login;
     $chamilo_uid = external_add_user($chamilo_user);
-    if ($chamilo_uid !== false) {
+
+    $chamiloUser = $em->find('ChamiloUserBundle:User', $chamilo_uid);
+
+    if ($chamiloUser) {
         $loginFailed = false;
-        $_user['user_id'] = $chamilo_uid;
-        $_user['status'] = (isset($chamilo_user['status']) ? $chamilo_user['status'] : 5);
+        $_user['user_id'] = $chamiloUser->getId();
+        $_user['status'] = $chamiloUser->getStatus();
         $_user['uidReset'] = true;
         Session::write('_user', $_user);
         $uidReset = true;
         // Is user admin?
         if ($chamilo_user['admin'] === true) {
             $is_platformAdmin = true;
-            Database::query("INSERT INTO admin values ('$chamilo_uid')");
+            Database::query("INSERT INTO admin values ('{$chamiloUser->getId()}')");
         }
-        Event::event_login($chamilo_uid);
+        Event::event_login($chamiloUser->getId());
+
+        MessageManager::sendNotificationByRegisteredUser($chamiloUser);
     }
 } else {
     $loginFailed = true;
     $uidReset = false;
-    unset($_user['user_id']);
 }

+ 39 - 73
main/chat/chat.php

@@ -1,92 +1,58 @@
 <?php
 /* For licensing terms, see /license.txt */
 
-/**
- * Chat tool
- * @package chamilo.chat
- */
+define('CHAMILO_LOAD_WYSIWYG', false);
 
 require_once '../inc/global.inc.php';
-$current_course_tool  = TOOL_CHAT;
-$this_section = SECTION_COURSES;
-$nameTools = get_lang('ToolChat');
 
-$origin = isset($_GET["origin"]) ? Security::remove_XSS($_GET["origin"]) : null;
-$target = isset($_GET["target"]) ? Security::remove_XSS($_GET["target"]) : null;
+api_protect_course_script(true);
 
-if ($origin != 'whoisonline') {
-    api_protect_course_script(true);
-} else {
-    $origin = $_SESSION['origin'];
-    $target = $_SESSION['target'];
-    $_SESSION['origin']= $origin;
-    $_SESSION['target']= $target;
-}
-
-api_protect_course_group(GroupManager::GROUP_TOOL_CHAT, false);
-
-/*  TRACKING */
 Event::event_access_tool(TOOL_CHAT);
-header('Content-Type: text/html; charset=UTF-8');
 
-/*
- * Choose CSS style (platform's, user's, or course's)
- */
-$my_style = api_get_visual_theme();
-
-$mycourseid = api_get_course_id();
-if (!empty($mycourseid) && $mycourseid != -1) {
-	$open_chat_window = api_get_course_setting('allow_open_chat_window');
+// View
+$externalCSS = [
+    'jquery-emojiarea/jquery.emojiarea.css',
+    'jquery-textcomplete/jquery.textcomplete.css',
+    'emojione/css/emojione.min.css',
+    'emojione/css/autocomplete.css',
+    'highlight/styles/github.css'
+];
+
+foreach ($externalCSS as $css) {
+    $htmlHeadXtra[] = api_get_css(api_get_path(WEB_LIBRARY_JS_PATH) . $css);
 }
 
-$courseCode = Security::remove_XSS($_GET['cidReq']);
-
-?>
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="UTF-8" />
-<link rel="stylesheet" type="text/css" href="<?php echo api_get_path(WEB_CSS_PATH); ?>chat.css">
-<?php
-echo'<title>'.get_lang('Chat').' - '.$mycourseid.' - '.api_get_setting('siteName').'</title>';
-
-$groupId = api_get_group_id();
+$htmlHeadXtra[] = api_get_css(api_get_path(WEB_CSS_PATH) . 'chat.css');
+$htmlHeadXtra[] = api_get_css(api_get_path(WEB_CSS_PATH) . 'markdown.css');
 
-// If it is a group chat then the breadcrumbs.
-if (!empty($groupId)) {
-	$group_properties  = GroupManager :: get_group_properties($groupId);
-    $interbreadcrumb[] = array(
-        'url' => api_get_path(WEB_CODE_PATH).'group/group.php?'.api_get_cidreq(),
-        'name' => get_lang('Groups')
-    );
-	$interbreadcrumb[] = array(
-        'url' => api_get_path(WEB_CODE_PATH).'group/group_space.php?'.api_get_cidreq(),
-        'name' => get_lang('GroupSpace').' '.$group_properties['name']
-    );
-	$noPHP_SELF = true;
-	$shortBanner = false;
-	$add_group_to_title = ' ('.$group_properties['name'].')';
-	$groupfilter = 'group_id="'.$groupId.'"';
-} else {
-	$groupfilter = 'group_id=0';
-}
+$externalJS = [
+    'highlight/highlight.pack.js',
+    'jquery-textcomplete/jquery.textcomplete.js',
+    'emojione/js/emojione.min.js',
+    'jquery-emojiarea/jquery.emojiarea.js'
+];
 
-if (empty($open_chat_window)) {
-    Display::display_header($tool_name, 'Chat');
+foreach ($externalJS as $js) {
+    $htmlHeadXtra[] = api_get_js($js);
 }
 
-$url = api_get_path(WEB_CODE_PATH).'chat/';
-$params = api_get_cidreq();
+$iconList = [];
 
-echo '<div class="page-chat">';
-echo '<iframe src="'.$url.'chat_whoisonline.php?'.$params.'" name="chat_whoisonline" scrolling="no" style="height:550px; width:35%; border: 0px none; float:left"></iframe>';
-echo '<iframe src="'.$url.'chat_chat.php?origin='.$origin.'&target='.$target.'&'.$params.'" name="chat_chat" id="chat_chat" scrolling="auto" height="380" style="width:65%; border: 0px none; float:right"></iframe>';
-echo '<iframe src="'.$url.'chat_message.php?'.$params.'" name="chat_message" scrolling="no" height="182px" style="width:65%; border: 0px none; float:right"></iframe>';
-echo '<iframe src="'.$url.'chat_hidden.php?'.$params.'" name="chat_hidden" height="0px" style="height:0px; border: 0px none"></iframe>';
-echo '</div>';
+foreach (Emojione\Emojione::$shortcode_replace as $key => $icon) {
+    if (!in_array($key, CourseChatUtils::getEmojisToInclude())) {
+        continue;
+    }
 
-if (empty($open_chat_window)) {
-    Display::display_footer();
+    $iconList[$key] = strtoupper($icon) . '.png';
 }
 
-echo '</html>';
+$view = new Template(get_lang('Chat'), false, false, false, true, false);
+$view->assign('icons', $iconList);
+$view->assign('emoji_strategy', CourseChatUtils::getEmojiStrategry());
+$view->assign('emoji_smile', \Emojione\Emojione::toImage(':smile:'));
+
+$template = $view->get_template('chat/chat.tpl');
+$content = $view->fetch($template);
+
+$view->assign('content', $content);
+$view->display_one_col_template();

+ 0 - 217
main/chat/chat_chat.php

@@ -1,217 +0,0 @@
-<?php
-/* For licensing terms, see /license.txt */
-
-/**
- *	Chat frame that shows the message list
- *
- *	@author Olivier Brouckaert
- *	@package chamilo.chat
- */
-
-define('FRAME', 'chat');
-
-require_once '../inc/global.inc.php';
-
-$course = $_GET['cidReq'];
-$session_id = api_get_session_id();
-$group_id 	= api_get_group_id();
-$userId = api_get_user_id();
-$_course = api_get_course_info();
-$time = api_get_utc_datetime();
-
-// if we have the session set up
-if (!empty($course)) {
-    $reset = isset($_GET['reset']) ? (bool)$_GET['reset'] : null;
-    $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
-    $query = "SELECT username FROM $tbl_user WHERE user_id='".$userId."'";
-    $result = Database::query($query);
-
-    list($pseudo_user) = Database::fetch_row($result);
-
-    $isAllowed = !(empty($pseudo_user) || !$_cid);
-    $isMaster = (bool)api_is_course_admin();
-
-    $date_now = date('Y-m-d');
-    $basepath_chat = '';
-    $document_path = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document';
-    if (!empty($group_id)) {
-        $group_info = GroupManager :: get_group_properties($group_id);
-        $basepath_chat = $group_info['directory'].'/chat_files';
-    } else {
-        $basepath_chat = '/chat_files';
-    }
-    $chat_path = $document_path.$basepath_chat.'/';
-    $TABLEITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
-    $course_id = api_get_course_int_id();
-
-    if (!is_dir($chat_path)) {
-        if (is_file($chat_path)) {
-            @unlink($chat_path);
-        }
-
-        if (!api_is_anonymous()) {
-            @mkdir($chat_path, api_get_permissions_for_new_directories());
-            // Save chat files document for group into item property
-            if (!empty($group_id)) {
-                $doc_id = add_document($_course, $basepath_chat, 'folder', 0, 'chat_files');
-                api_item_property_update(
-                    $_course,
-                    TOOL_DOCUMENT,
-                    $doc_id,
-                    'FolderCreated',
-                    null,
-                    $group_id,
-                    null,
-                    null,
-                    null
-                );
-            }
-        }
-    }
-
-    $filename_chat = '';
-    if (!empty($group_id)) {
-        $filename_chat = 'messages-'.$date_now.'_gid-'.$group_id.'.log.html';
-    } else if (!empty($session_id)) {
-        $filename_chat = 'messages-'.$date_now.'_sid-'.$session_id.'.log.html';
-    } else {
-        $filename_chat = 'messages-'.$date_now.'.log.html';
-    }
-
-	if (!file_exists($chat_path.$filename_chat)) {
-		@fclose(fopen($chat_path.$filename_chat, 'w'));
-		if (!api_is_anonymous()) {
-			$doc_id = add_document($_course, $basepath_chat.'/'.$filename_chat, 'file', 0, $filename_chat);
-            api_item_property_update(
-                $_course,
-                TOOL_DOCUMENT,
-                $doc_id,
-                'DocumentAdded',
-                $userId,
-                $group_id,
-                null,
-                null,
-                null,
-                $session_id
-            );
-            api_item_property_update(
-                $_course,
-                TOOL_DOCUMENT,
-                $doc_id,
-                'invisible',
-                $userId,
-                $group_id,
-                null,
-                null,
-                null,
-                $session_id
-            );
-            item_property_update_on_folder($_course, $basepath_chat, $userId);
-		}
-	}
-
-	$basename_chat = '';
-	if (!empty($group_id)) {
-		$basename_chat = 'messages-'.$date_now.'_gid-'.$group_id;
-	} else if (!empty($session_id)) {
-		$basename_chat = 'messages-'.$date_now.'_sid-'.$session_id;
-	} else {
-		$basename_chat = 'messages-'.$date_now;
-	}
-
-	if ($reset && $isMaster) {
-
-		$i = 1;
-		while (file_exists($chat_path.$basename_chat.'-'.$i.'.log.html')) {
-			$i++;
-		}
-
-		@rename($chat_path.$basename_chat.'.log.html', $chat_path.$basename_chat.'-'.$i.'.log.html');
-		@fclose(fopen($chat_path.$basename_chat.'.log.html', 'w'));
-		$doc_id = add_document($_course, $basepath_chat.'/'.$basename_chat.'-'.$i.'.log.html', 'file', filesize($chat_path.$basename_chat.'-'.$i.'.log.html'), $basename_chat.'-'.$i.'.log.html');
-
-        api_item_property_update(
-            $_course,
-            TOOL_DOCUMENT,
-            $doc_id,
-            'DocumentAdded',
-            $userId,
-            $group_id,
-            null,
-            null,
-            null,
-            $session_id
-        );
-        api_item_property_update(
-            $_course,
-            TOOL_DOCUMENT,
-            $doc_id,
-            'invisible',
-            $userId,
-            $group_id,
-            null,
-            null,
-            null,
-            $session_id
-        );
-        item_property_update_on_folder($_course, $basepath_chat, $userId);
-
-        $doc_id = DocumentManager::get_document_id(
-            $_course,
-            $basepath_chat.'/'.$basename_chat.'.log.html'
-        );
-
-		update_existing_document($_course, $doc_id, 0);
-	}
-
-	$remove = 0;
-	$content = array();
-	if (file_exists($chat_path.$basename_chat.'.log.html')) {
-		$content = file($chat_path.$basename_chat.'.log.html');
-		$nbr_lines = sizeof($content);
-		$remove = $nbr_lines - 100;
-	}
-
-	if ($remove < 0) {
-		$remove = 0;
-	}
-
-	array_splice($content, 0, $remove);
-	require 'header_frame.inc.php';
-
-	if (isset($_GET['origin']) && $_GET['origin'] == 'whoisonline') {
-	    //the caller
-		$content[0] = get_lang('CallSent').'<br />'.$content[0];
-	}
-	if (isset($_GET['origin']) && $_GET['origin'] == 'whoisonlinejoin') {
-	    //the joiner (we have to delete the chat request to him when he joins the chat)
-		$track_user_table = Database::get_main_table(TABLE_MAIN_USER);
-		$sql = "UPDATE $track_user_table SET
-                    chatcall_user_id = '',
-                    chatcall_date = '',
-                    chatcall_text=''
-		        WHERE (user_id = ".$userId.")";
-		$result = Database::query($sql);
-	}
-        
-	echo '<div id="content-chat"';
-	foreach ($content as & $this_line) {
-        echo $this_line;
-	}
-	echo '</div>';
-	echo '<a name="bottom" style="text-decoration:none;">&nbsp;</a>';
-	if ($isMaster || $is_courseCoach) {
-		$rand = mt_rand(1, 1000);
-		echo '<div id="clear-chat">';
-		echo '<a class="btn btn-danger btn-small " href="'.api_get_self().'?rand='.$rand.'&reset=1&'.api_get_cidreq().'#bottom" onclick="javascript: if(!confirm(\''.addslashes(api_htmlentities(get_lang('ConfirmReset'), ENT_QUOTES)).'\')) return false;">'.
-            get_lang('ClearList').
-            '</a>';
-		echo '</div>';
-	}
-} else {
-	echo '</div>';
-	require 'header_frame.inc.php';
-	$message = get_lang('CloseOtherSession');
-	Display :: display_error_message($message);
-}
-require 'footer_frame.inc.php';

+ 0 - 242
main/chat/chat_functions.lib.php

@@ -1,242 +0,0 @@
-<?php
-/* For licensing terms, see /license.txt */
-/**
- *	@package chamilo.chat
- */
-use Michelf\MarkdownExtra;
-
-/**
- * @author isaac flores paz
- * @param integer $user_id
- *
- * @return boolean
- * @todo this function need more parameters seems not to be use anymore
- * @deprecated fix this function or create another
- */
-function user_connected_in_chat($user_id)
-{
- 	$tbl_chat_connected = Database::get_course_table(TABLE_CHAT_CONNECTED);
-    $user_id 	= intval($user_id);
- 	$session_id = api_get_session_id();
-    $group_id   = api_get_group_id();
-    $course_id  = api_get_course_int_id();
-
-	if (!empty($group_id)) {
-		$extra_condition = " AND to_group_id = '$group_id'";
-	} else {
-		$extra_condition = api_get_session_condition($session_id);
-	}
-
- 	$sql = 'SELECT COUNT(*) AS count
- 	        FROM '.$tbl_chat_connected .' c
- 	        WHERE
- 	            c_id = '.$course_id.' AND
- 	            user_id='.$user_id.$extra_condition;
- 	$result = Database::query($sql);
- 	$count  = Database::fetch_array($result,'ASSOC');
-
- 	return $count['count'] == 1;
-}
-
-/**
- * @param integer
- * @return void
- */
-function exit_of_chat($user_id)
-{
-    $user_id = intval($user_id);
-    $list_course = CourseManager::get_courses_list_by_user_id($user_id);
-    $tbl_chat_connected = Database::get_course_table(TABLE_CHAT_CONNECTED);
-
-    foreach ($list_course as $course) {
-        $response = user_connected_in_chat($user_id);
-
-        $sql = 'DELETE FROM '.$tbl_chat_connected.'
-                WHERE c_id = '.$course['real_id'].' AND user_id = '.$user_id;
-        Database::query($sql);
-
-    }
-}
-
-/**
- * @return void
- */
-function disconnect_user_of_chat()
-{
-    $list_info_user_in_chat = users_list_in_chat();
-    $course_id = api_get_course_int_id();
-    $groupId = api_get_group_id();
-    $now = time();
-    $cd_date = date('Y-m-d', $now);
-    $cdate_h = date('H', $now);
-    $cdate_m = date('i', $now);
-    $cdate_s = date('s', $now);
-	$cd_count_time_seconds = $cdate_h*3600 + $cdate_m*60 + $cdate_s;
-
-    if (is_array($list_info_user_in_chat) && count($list_info_user_in_chat) > 0) {
-        foreach ($list_info_user_in_chat as $list_info_user) {
-            $date_db_date = date('Y-m-d', api_strtotime($list_info_user['last_connection'], 'UTC'));
-            $date_db_h  = date('H', api_strtotime($list_info_user['last_connection'], 'UTC'));
-            $date_db_m  = date('i', api_strtotime($list_info_user['last_connection'], 'UTC'));
-            $date_db_s  = date('s', api_strtotime($list_info_user['last_connection'], 'UTC'));
-            $date_count_time_seconds = $date_db_h * 3600 + $date_db_m * 60 + $date_db_s;
-            if ($cd_date == $date_db_date) {
-                if (($cd_count_time_seconds - $date_count_time_seconds) > 5) {
-                    $tbl_chat_connected = Database::get_course_table(TABLE_CHAT_CONNECTED);
-                    $sql = 'DELETE FROM '.$tbl_chat_connected.'
-                            WHERE
-                                c_id = '.$course_id.' AND
-                                user_id = '.$list_info_user['user_id'].' AND
-                                to_group_id = '.$groupId.'
-                            ';
-                    Database::query($sql);
-                }
-            }
-        }
-    }
-}
-
-/**
- * @return array user list in chat
- */
-function users_list_in_chat()
-{
-	$list_users_in_chat = array();
- 	$tbl_chat_connected = Database::get_course_table(TABLE_CHAT_CONNECTED);
-    $course_id = api_get_course_int_id();
-
- 	$session_id = api_get_session_id();
-    $group_id   = api_get_group_id();
-
-	if (!empty($group_id)) {
-		$extra_condition = " WHERE to_group_id = '$group_id'";
-	} else{
-		$extra_condition = api_get_session_condition($session_id, false);
-	}
-    $extra_condition.= " AND c_id = $course_id ";
- 	$sql = 'SELECT user_id, last_connection FROM '.$tbl_chat_connected.$extra_condition;
- 	$result = Database::query($sql);
- 	while ($row = Database::fetch_array($result, 'ASSOC')) {
- 		$list_users_in_chat[] = $row;
- 	}
-
- 	return $list_users_in_chat;
-}
-
-/**
- * @param string $message
- * @param array $_course
- * @param int $group_id
- * @param int $session_id
- * @param bool $preview
- */
-function saveMessage($message, $userId, $_course, $session_id, $group_id, $preview = true)
-{
-    $userInfo = api_get_user_info($userId);
-    $fullName = $userInfo['complete_name'];
-    $isMaster = (bool)api_is_course_admin();
-
-    $document_path = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document';
-    if (!empty($group_id)) {
-        $group_info = GroupManager :: get_group_properties($group_id);
-        $basepath_chat = $group_info['directory'].'/chat_files';
-    } else {
-        $basepath_chat = '/chat_files';
-    }
-    $chat_path = $document_path.$basepath_chat.'/';
-
-    if (!is_dir($chat_path)) {
-        if (is_file($chat_path)) {
-            @unlink($chat_path);
-        }
-    }
-
-    $date_now = date('Y-m-d');
-    $message = trim($message);
-    $timeNow = date('d/m/y H:i:s');
-
-    if (!empty($group_id)) {
-        $basename_chat = 'messages-'.$date_now.'_gid-'.$group_id;
-    } elseif (!empty($session_id)) {
-        $basename_chat = 'messages-'.$date_now.'_sid-'.$session_id;
-    } else {
-        $basename_chat = 'messages-'.$date_now;
-    }
-
-    if (!api_is_anonymous()) {
-        if (!empty($message)) {
-            Emojione\Emojione::$imagePathPNG = api_get_path(WEB_LIBRARY_PATH).'javascript/emojione/png/';
-            Emojione\Emojione::$ascii = true;
-
-            // Parsing emojis
-            $message = Emojione\Emojione::toImage($message);
-            // Parsing text to understand markdown (code highlight)
-            $message = MarkdownExtra::defaultTransform($message);
-            // Security XSS
-            $message = Security::remove_XSS($message);
-
-            if ($preview == true) {
-                return $message;
-            }
-
-            if (!file_exists($chat_path.$basename_chat.'.log.html')) {
-                $doc_id = add_document(
-                    $_course,
-                    $basepath_chat . '/' . $basename_chat . '.log.html',
-                    'file',
-                    0,
-                    $basename_chat . '.log.html'
-                );
-                api_item_property_update(
-                    $_course,
-                    TOOL_DOCUMENT,
-                    $doc_id,
-                    'DocumentAdded',
-                    $userId,
-                    $group_id,
-                    null,
-                    null,
-                    null,
-                    $session_id
-                );
-                api_item_property_update(
-                    $_course,
-                    TOOL_DOCUMENT,
-                    $doc_id,
-                    'invisible',
-                    $userId,
-                    $group_id,
-                    null,
-                    null,
-                    null,
-                    $session_id
-                );
-                item_property_update_on_folder(
-                    $_course,
-                    $basepath_chat,
-                    $userId
-                );
-            } else {
-                $doc_id = DocumentManager::get_document_id(
-                    $_course,
-                    $basepath_chat.'/'.$basename_chat.'.log.html'
-                );
-            }
-
-            $fp = fopen($chat_path.$basename_chat.'.log.html', 'a');
-            $userPhoto = UserManager::getUserPicture($userId, USER_IMAGE_SIZE_MEDIUM);
-            $filePhoto = '<img class="chat-image" src="'.$userPhoto.'"/>';
-            if ($isMaster) {
-                fputs($fp, '<div class="message-teacher"><div class="content-message"><div class="chat-message-block-name">'.$fullName.'</div><div class="chat-message-block-content">'.$message.'</div><div class="message-date">'.$timeNow.'</div></div><div class="icon-message"></div>'.$filePhoto.'</div>'."\n");
-            } else {
-                fputs($fp, '<div class="message-student">'.$filePhoto.'<div class="icon-message"></div><div class="content-message"><div class="chat-message-block-name">'.$fullName.'</div><div class="chat-message-block-content">'.$message.'</div><div class="message-date">'.$timeNow.'</div></div></div>'."\n");
-            }
-            fclose($fp);
-
-            $chat_size = filesize($chat_path.$basename_chat.'.log.html');
-
-            update_existing_document($_course, $doc_id, $chat_size);
-            item_property_update_on_folder($_course, $basepath_chat, $userId);
-        }
-    }
-}

+ 0 - 126
main/chat/chat_hidden.php

@@ -1,126 +0,0 @@
-<?php
-/* For licensing terms, see /license.txt */
-
-/**
- *	Hidden frame that refreshes the visible frames when a modification occurs
- *
- *	@author Olivier Brouckaert
- *	@package chamilo.chat
- */
-
-define('FRAME', 'hidden');
-
-require_once '../inc/global.inc.php';
-require_once 'chat_functions.lib.php';
-
-$tbl_user = Database::get_main_table(TABLE_MAIN_USER);
-$tbl_chat_connected = Database::get_course_table(TABLE_CHAT_CONNECTED);
-$userId = api_get_user_id();
-$course_id = api_get_course_int_id();
-
-$query = "SELECT username FROM $tbl_user WHERE user_id='".$userId."'";
-$result = Database::query($query);
-
-list($pseudo_user) = Database::fetch_row($result);
-
-$isAllowed = !(empty($pseudo_user) || !$_cid);
-$isMaster = (bool)api_is_course_admin();
-
-$date_now = date('Y-m-d');
-
-$group_id = api_get_group_id();
-$session_id = api_get_session_id();
-$session_condition = api_get_session_condition($session_id);
-$group_condition = " AND to_group_id = '$group_id'";
-
-$extra_condition = '';
-if (!empty($group_id)) {
-	$extra_condition = $group_condition;
-} else {
-	$extra_condition = $session_condition;
-}
-
-$extra_condition.= " AND c_id = $course_id";
-
-// get chat path
-$chat_path = '';
-$document_path = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document';
-if (!empty($group_id)) {
-	$group_info = GroupManager :: get_group_properties($group_id);
-	$chat_path = $document_path.$group_info['directory'].'/chat_files/';
-} else {
-	$chat_path = $document_path.'/chat_files/';
-}
-
-// get chat file
-$basename_chat = '';
-if (!empty($group_id)) {
-	$basename_chat = 'messages-'.$date_now.'_gid-'.$group_id;
-} elseif (!empty($session_id)) {
-	$basename_chat = 'messages-'.$date_now.'_sid-'.$session_id;
-} else {
-	$basename_chat = 'messages-'.$date_now;
-}
-
-$chat_size_old = isset($_POST['chat_size_old']) ? intval($_POST['chat_size_old']) : null;
-
-$file = $chat_path.$basename_chat.'.log.html';
-$chat_size_new = 0;
-if (file_exists($file)) {
-    $chat_size_new = filesize($file);
-}
-
-$sql = "SELECT user_id FROM $tbl_chat_connected
-        WHERE user_id='".$userId."' $extra_condition";
-$result = Database::query($sql);
-
-// The user_id exists so we must do an UPDATE and not a INSERT
-$current_time = api_get_utc_datetime();
-
-if (Database::num_rows($result) == 0) {
-	$query = "INSERT INTO $tbl_chat_connected(c_id, user_id, last_connection,session_id,to_group_id)
-	          VALUES($course_id, '".$userId."','$current_time','$session_id','$group_id')";
-    Database::query($query);
-    $id = Database::insert_id();
-    if ($id) {
-        $sql = "UPDATE $tbl_chat_connected SET id = iid WHERE iid = $id";
-        Database::query($sql);
-    }
-} else {
-	$query = "UPDATE $tbl_chat_connected SET
-	          last_connection='".$current_time."'
-	          WHERE c_id = $course_id AND user_id='".$userId."' AND session_id='$session_id' AND to_group_id='$group_id'";
-    Database::query($query);
-}
-
-$query = "SELECT COUNT(user_id) FROM $tbl_chat_connected
-          WHERE last_connection>'".date('Y-m-d H:i:s',time()-60*5)."' $extra_condition";
-$result = Database::query($query);
-
-$connected_old = isset($_POST['connected_old']) ? intval($_POST['connected_old']) : null;
-list($connected_new) = Database::fetch_row($result);
-
-/*disconnected user of chat*/
-disconnect_user_of_chat();
-require 'header_frame.inc.php';
-?>
-<form name="formHidden" method="post" action="<?php echo api_get_self().'?'.api_get_cidreq(); ?>">
-<input type="hidden" name="chat_size_old" value="<?php echo $chat_size_new; ?>">
-<input type="hidden" name="connected_old" value="<?php echo $connected_new; ?>">
-</form>
-<?php
-
-if (isset($_SESSION["origin"]) && $_SESSION["origin"] == 'whoisonline') {
-    //check if our target has denied our request or not
-    $talk_to = $_SESSION["target"];
-    $track_user_table = Database::get_main_table(TABLE_MAIN_USER);
-    $sql = "select chatcall_text from $track_user_table where ( user_id = $talk_to )";
-    $result = Database::query($sql);
-    $row = Database::fetch_array($result);
-    if ($row['chatcall_text'] == 'DENIED') {
-        echo "<script language=\"javascript\" type=\"text/javascript\"> alert('".get_lang('ChatDenied')."'); </script>";
-        $sql = "update $track_user_table set chatcall_user_id = '', chatcall_date = '', chatcall_text='' WHERE (user_id = $talk_to)";
-        $result = Database::query($sql);
-    }
-}
-require 'footer_frame.inc.php';

+ 0 - 128
main/chat/chat_message.php

@@ -1,128 +0,0 @@
-<?php
-/* For licensing terms, see /license.txt */
-
-/**
- *	Allows to type the messages that will be displayed on chat_chat.php
- *
- *	@author Olivier Brouckaert
- * 	Modified by Alex Aragón (BeezNest)
- *	@package chamilo.chat
- */
-define('FRAME', 'message');
-
-require_once '../inc/global.inc.php';
-require_once api_get_path(SYS_CODE_PATH).'chat/chat_functions.lib.php';
-
-$userId = api_get_user_id();
-$userInfo = api_get_user_info();
-$course = api_get_course_id();
-$session_id = api_get_session_id();
-$group_id = api_get_group_id();
-$_course = api_get_course_info();
-
-// Juan Carlos Raña inserted smileys and self-closing window.
-?>
-<script>
-function close_chat_window() {
-    var chat_window = top.window.self;
-    chat_window.opener = top.window.self;
-    chat_window.top.close();
-}
-</script>
-<?php
-
-// Mode open in a new window: close the window when there isn't an user login
-if (empty($userId)) {
-    echo '<script languaje="javascript" type="text/javascript"> close_chat_window(); </script>';
-} else {
-    api_protect_course_script();
-}
-
-if (empty($course) || empty($userId)) {
-    exit;
-}
-
-/*	Constants and variables */
-$tbl_user = Database::get_main_table(TABLE_MAIN_USER);
-$sent = isset($_REQUEST['sent']) ? $_REQUEST['sent'] : null;
-
-require 'header_frame.inc.php';
-$chat_size = 0;
-
-if ($sent) {
-    saveMessage(
-        $_POST['message'],
-        $userId,
-        $_course,
-        $session_id,
-        $group_id,
-        false
-    );
-}
-?>
-<form
-    id="formMessage"
-    name="formMessage"
-    method="post"
-    action="<?php echo api_get_self().'?'.api_get_cidreq(); ?>" onsubmit="javascript: if(document.formMessage.message.value == '') { alert('<?php echo addslashes(api_htmlentities(get_lang('TypeMessage'), ENT_QUOTES)); ?>'); document.formMessage.message.focus(); return false; }"
-    autocomplete="off"
->
-    <input type="hidden" name="sent" value="1">
-    <div class="message-form-chat">
-        <div class="tabbable">
-            <ul class="nav nav-tabs">
-                <li class="active">
-                    <a href="#tab1" data-toggle="tab">
-                        <?php echo get_lang('Write'); ?>
-                    </a>
-                </li>
-                <li>
-                    <a href="#tab2" id="preview" data-toggle="tab">
-                        <?php echo get_lang('Preview'); ?>
-                    </a>
-                </li>
-                <li>
-                    <a href="#tab3" id="emojis" data-toggle="tab">
-                        <?php echo Emojione\Emojione::toImage(':smile:'); ?>
-                    </a>
-                </li>
-            </ul>
-            <div class="tab-content">
-                <div class="tab-pane active" id="tab1">
-                    <table border="0" cellpadding="5" cellspacing="0" width="100%">
-                        <tr>
-                            <td width="320" valign="middle">
-                                <?php
-                                $talkboxsize = (api_get_course_setting('allow_open_chat_window')) ? 'width: 350px; height: 80px' : 'width: 450px; height: 35px';
-                                ?>
-                                <textarea id="message" class="message-text" name="message" style=" <?php echo $talkboxsize; ?>"></textarea>
-                            </td>
-                        </tr>
-                        <tr>
-                            <td>
-                                <div class="btn-group">
-                                    <button id="send" type="submit" value="<?php echo get_lang('Send'); ?>" class="btn btn-primary">
-                                        <?php echo get_lang('Send'); ?>
-                                    </button>
-                                </div>
-                            </td>
-                        </tr>
-                    </table>
-                </div>
-                <div class="tab-pane" id="tab2">
-                    <table border="0" cellpadding="5" cellspacing="0" width="100%">
-                        <tr>
-                            <td width="320" valign="middle">
-                                <div id="html-preview" class="emoji-wysiwyg-editor-preview">
-                                </div>
-                            </td>
-                        </tr>
-                    </table>
-                </div>
-            </div>
-        </div>
-    </div>
-    </form>
-<?php
-
-require 'footer_frame.inc.php';

+ 0 - 162
main/chat/chat_whoisonline.php

@@ -1,162 +0,0 @@
-<?php
-/* For licensing terms, see /license.txt */
-/**
- *	Shows the list of connected users
- *
- *	@author Olivier Brouckaert
- *	@package chamilo.chat
- */
-
-define('FRAME', 'online');
-
-require_once '../inc/global.inc.php';
-
-$course = api_get_course_id();
-$courseInfo = api_get_course_info();
-$group_id = api_get_group_id();
-$session_id = api_get_session_id();
-$user_id = api_get_user_id();
-$group_condition = " AND to_group_id = '$group_id'";
-
-$extra_condition = '';
-if (!empty($group_id)) {
-    $extra_condition = $group_condition;
-}
-
-if (!empty($course)) {
-    $showPic = isset($_GET['showPic']) ? intval($_GET['showPic']) : null;
-    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
-    $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
-    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
-    $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
-    $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
-    $tbl_chat_connected = Database::get_course_table(TABLE_CHAT_CONNECTED);
-
-    $query = "SELECT username FROM $tbl_user WHERE user_id='".$user_id."'";
-    $result = Database::query($query);
-
-    list($pseudo_user) = Database::fetch_array($result);
-
-	$isAllowed = !(empty($pseudo_user) || !$_cid);
-	$isMaster = api_is_course_admin();
-    $date_inter = api_get_utc_datetime(time() - 120);
-
-    $users = array();
-    $course_id = api_get_course_int_id();
-
-    if (empty($session_id)) {
-		$sql = "SELECT DISTINCT
-		            t1.user_id,
-		            username,
-		            firstname,
-		            lastname,
-		            picture_uri,
-		            email,
-		            t3.status
-                FROM $tbl_user t1, $tbl_chat_connected t2, $tbl_course_user t3
-                WHERE
-                    t2.c_id = $course_id AND
-                    t1.user_id=t2.user_id AND
-                    t3.user_id=t2.user_id AND
-                    t3.relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
-                    t3.c_id = '".$courseInfo['real_id']."' AND
-                    t2.last_connection>'".$date_inter."' $extra_condition
-                ORDER BY username";
-
-        $result = Database::query($sql);
-        $users = Database::store_result($result);
-	} else {
-        $session_condition = api_get_session_condition($session_id, true, false, 't3.session_id');
-		// select learners
-		$query = "SELECT DISTINCT t1.user_id,username,firstname,lastname,picture_uri,email
-                  FROM $tbl_user t1, $tbl_chat_connected t2, $tbl_session_course_user t3
-		          WHERE
-		          t2.c_id = $course_id AND
-		          t1.user_id=t2.user_id AND t3.user_id=t2.user_id AND
-		          t3.session_id = '".$session_id."' AND
-		          t3.c_id = '".$courseInfo['real_id']."' AND
-		          t2.last_connection>'".$date_inter."' $session_condition
-		          ORDER BY username";
-		$result = Database::query($query);
-		while ($learner = Database::fetch_array($result)) {
-            $users[$learner['user_id']] = $learner;
-		}
-
-		// select session coach
-		$query = "SELECT DISTINCT t1.user_id,username,firstname,lastname,picture_uri,email
-		          FROM $tbl_user t1,$tbl_chat_connected t2,$tbl_session t3
-		          WHERE
-					t2.c_id = $course_id AND
-					t1.user_id=t2.user_id AND
-					t3.id_coach=t2.user_id AND
-					t3.id = '".$session_id."' AND
-					t2.last_connection > '".$date_inter."'
-					$extra_condition
-				  ORDER BY username";
-		$result = Database::query($query);
-		if ($coach = Database::fetch_array($result)) {
-			$users[$coach['user_id']] = $coach;
-		}
-
-		// select session course coach
-		$query = "SELECT DISTINCT t1.user_id,username,firstname,lastname,picture_uri,email
-				FROM $tbl_user t1,$tbl_chat_connected t2,$tbl_session_course_user t3
-				WHERE
-					t2.c_id = $course_id AND
-					t1.user_id=t2.user_id
-					AND t3.user_id =t2.user_id AND t3.status=2
-					AND t3.session_id = '".$session_id."'
-					AND t3.c_id = '".$course_id."'
-					AND t2.last_connection>'".$date_inter."' $extra_condition
-				ORDER BY username";
-
-		$result = Database::query($query);
-		$course_coaches = array();
-		while ($coaches = Database::fetch_array($result)) {
-			$users[$coaches['user_id']] = $coaches;
-		}
-	}
-	require 'header_frame.inc.php';
-
-	?>
-	<div class="user-connected">
-	<div id="user-online-scroll" class="user-online">
-		<div class="title"><?php echo get_lang('Users'); ?> <?php echo get_lang('Connected'); ?></div>
-		<div class="scrollbar"><div class="track"><div class="thumb"><div class="end"></div></div></div></div>
-		<div class="scrollbar-inner viewport"><div id="hidden" class="overview">
-		<ul class="profile list-group">
-			<?php
-            foreach ($users as & $user) {
-                if (empty($session_id)) {
-                    $status = $user['status'];
-                } else {
-                    $status = CourseManager::is_course_teacher($user['user_id'], api_get_course_id()) ? 1 : 5;
-                }
-                $fileUrl = UserManager::getUserPicture($user['user_id'], USER_IMAGE_SIZE_MEDIUM);
-                $url_user_profile=api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user['user_id'].'&';
-			?>
-			<li class="list-group-item">
-				<img src="<?php echo $fileUrl;?>" border="0" width="50" alt="" class="user-image-chat" />
-				<div class="user-name">
-					<a href="<?php echo $url_user_profile; ?>" target="_blank">
-                        <?php echo api_get_person_name($user['firstname'], $user['lastname']); ?>
-                    </a>
-					<?php
-                        if ($status == 1) {
-                            echo Display::return_icon('teachers.gif', get_lang('Teacher'), array('height' => '18'));
-                        } else {
-                            echo Display::return_icon('students.gif', get_lang('Student'), array('height' => '18'));
-                        }
-					?>
-				</div>
-				<div class="user-email"><?php echo $user['username']; ?></div>
-			</li>
-			<?php
-            }
-            unset($users);
-        ?>
-		</ul>
-	</div></div></div></div>
-	<?php
-}
-require 'footer_frame.inc.php';

+ 0 - 17
main/chat/footer_frame.inc.php

@@ -1,17 +0,0 @@
-<?php
-/* For licensing terms, see /license.txt */
-
-/**
- *	Footer of each frame of the Chat tool
- *
- *	@author Olivier Brouckaert
- *	@package chamilo.chat
- */
-?>
-<audio id="audio">
-	<source src="<?php echo api_get_path(WEB_PATH);?>main/chat/sound/notification.wav" type="audio/wav"></source>
-	<source src="<?php echo api_get_path(WEB_PATH);?>main/chat/sound/notification.ogg" type="audio/ogg"></source>
-	<source src="<?php echo api_get_path(WEB_PATH);?>main/chat/sound/notification.mp3" type="audio/mpeg"></source>
-</audio>
-</body>
-</html>

File diff suppressed because it is too large
+ 0 - 147
main/chat/header_frame.inc.php


+ 2 - 1
main/course_info/tools.php

@@ -44,7 +44,7 @@ switch ($action) {
         }
 
         $interbreadcrumb[] = array('url' => api_get_self().'?'.api_get_cidreq(), 'name' => get_lang('CustomizeIcons'));
-        $toolName = $tool['name'];
+        $toolName = Security::remove_XSS(stripslashes($tool['name']));
 
         $currentUrl = api_get_self().'?action=edit_icon&id=' . $id.'&'.api_get_cidreq();
 
@@ -115,6 +115,7 @@ switch ($action) {
         $iconsTools .= Display::page_header(get_lang('CustomizeIcons'), null, 'h4');
         $iconsTools .= '<div class="row">';
         foreach ($toolList as $tool) {
+            $tool['name'] = Security::remove_XSS(stripslashes($tool['name']));
             $toolIconName = 'Tool' . api_underscore_to_camel_case($tool['name']);
             $toolIconName = isset($$toolIconName) ? get_lang($toolIconName) : $tool['name'];
 

+ 2 - 2
main/course_progress/index.php

@@ -50,8 +50,8 @@ $actions = array(
 );
 
 $action  = 'thematic_details';
-if (isset($_GET['action']) && in_array($_GET['action'],$actions)) {
-    $action = $_GET['action'];
+if (isset($_REQUEST['action']) && in_array($_REQUEST['action'], $actions)) {
+    $action = $_REQUEST['action'];
 }
 
 if (isset($_POST['action']) && $_POST['action'] == 'thematic_delete_select') {

+ 2 - 7
main/course_progress/thematic.php

@@ -190,13 +190,8 @@ if ($action == 'thematic_list') {
                             'index.php?' . api_get_cidreq() . '&' . http_build_query([
                                 'action' => 'thematic_advance_edit',
                                 'thematic_id' => $thematic['id'],
-                                'thematic_advance_id' => $thematic_advance['id'],
-                                'display' => 'no_header'
-                            ]),
-                            [
-                                'class' => 'ajax',
-                                'data-title' => get_lang('EditThematicAdvance')
-                            ]
+                                'thematic_advance_id' => $thematic_advance['id']
+                            ])
                         );
                         $edit_link  .= '<a onclick="javascript:if(!confirm(\''.get_lang('AreYouSureToDelete').'\')) return false;" href="index.php?'.api_get_cidreq().'&action=thematic_advance_delete&thematic_id='.$thematic['id'].'&thematic_advance_id='.$thematic_advance['id'].'">'.
                             Display::return_icon('delete.png',get_lang('Delete'),'',ICON_SIZE_SMALL).'</a></center>';

+ 36 - 2
main/course_progress/thematic_advance.php

@@ -22,8 +22,7 @@ if ($action == 'thematic_advance_add' || $action == 'thematic_advance_edit') {
     $form = new FormValidator(
         'thematic_advance',
         'POST',
-        'index.php?action=thematic_advance_list&thematic_id='.$thematic_id.'&'.api_get_cidreq(
-        )
+        api_get_self() . '?' . api_get_cidreq()
     );
     $form->addElement('header',  $header_form);
     //$form->addElement('hidden', 'thematic_advance_token',$token);
@@ -170,6 +169,41 @@ if ($action == 'thematic_advance_add' || $action == 'thematic_advance_edit') {
         }
     }
     $form->setDefaults($default);
+
+    if ($form->validate()) {
+        $values = $form->exportValues();
+
+        $thematic = new Thematic();
+        $thematic->set_thematic_advance_attributes(
+            isset($values['thematic_advance_id']) ? $values['thematic_advance_id']: null,
+            $values['thematic_id'],
+            $values['start_date_type'] == 1 && isset($values['attendance_select']) ? $values['attendance_select'] : 0,
+            $values['content'],
+            $values['start_date_type'] == 2 ? $values['custom_start_date'] : $values['start_date_by_attendance'],
+            $values['duration_in_hours']
+        );
+
+        $affected_rows = $thematic->thematic_advance_save();
+
+        if ($affected_rows) {
+            // get last done thematic advance before move thematic list
+            $last_done_thematic_advance = $thematic->get_last_done_thematic_advance();
+            // update done advances with de current thematic list
+            if (!empty($last_done_thematic_advance)) {
+                $thematic->update_done_thematic_advances($last_done_thematic_advance);
+            }
+        }
+
+        $redirectUrlParams = 'course_progress/index.php?' .  api_get_cidreq() . '&' .
+            http_build_query([
+                'action' => 'thematic_advance_list',
+                'thematic_id' => $values['thematic_id']
+            ]);
+
+        header('Location: ' . api_get_path(WEB_CODE_PATH) . $redirectUrlParams);
+        exit;
+    }
+
     $form->display();
 
 } else if ($action == 'thematic_advance_list') {

+ 7 - 54
main/course_progress/thematic_controller.php

@@ -425,60 +425,13 @@ class ThematicController
                     exit;
                 }
 
-                if ((isset($_REQUEST['start_date_type']) && $_REQUEST['start_date_type'] == 1 && empty($_REQUEST['start_date_by_attendance'])) ||
-                    (!empty($_REQUEST['duration_in_hours']) && !is_numeric($_REQUEST['duration_in_hours']))
-                ) {
-                    if ($_REQUEST['start_date_type'] == 1 && empty($_REQUEST['start_date_by_attendance'])) {
-                        $start_date_error = true;
-                        $data['start_date_error'] = $start_date_error;
-                    }
-
-                    if (!empty($_REQUEST['duration_in_hours']) && !is_numeric($_REQUEST['duration_in_hours'])) {
-                        $duration_error = true;
-                        $data['duration_error'] = $duration_error;
-                    }
-
-                    $data['action'] = $_REQUEST['action'];
-                    $data['thematic_id'] = $_REQUEST['thematic_id'];
-                    $data['attendance_select'] = $attendance_select;
-                    if (isset($_REQUEST['thematic_advance_id'])) {
-                        $data['thematic_advance_id'] = $_REQUEST['thematic_advance_id'];
-                        $thematic_advance_data = $thematic->get_thematic_advance_list($_REQUEST['thematic_advance_id']);
-                        $data['thematic_advance_data'] = $thematic_advance_data;
-                    }
-                } else {
-                    if (api_is_allowed_to_edit(null, true)) {
-                        $thematic_advance_id = isset($_REQUEST['thematic_advance_id']) ? $_REQUEST['thematic_advance_id'] : null;
-                        $thematic_id = $_REQUEST['thematic_id'];
-                        $content = isset($_REQUEST['content']) ? $_REQUEST['content'] : null;
-                        $duration = isset($_REQUEST['duration_in_hours']) ? $_REQUEST['duration_in_hours'] : null;
-                        if (isset($_REQUEST['start_date_type']) && $_REQUEST['start_date_type'] == 2) {
-                            $start_date = $_REQUEST['custom_start_date'];
-                            $attendance_id = 0;
-                        } else {
-                            $start_date = isset($_REQUEST['start_date_by_attendance']) ? $_REQUEST['start_date_by_attendance'] : null;
-                            $attendance_id = isset($_REQUEST['attendance_select']) ? $_REQUEST['attendance_select'] : null;
-                        }
-                        $thematic->set_thematic_advance_attributes(
-                            $thematic_advance_id,
-                            $thematic_id,
-                            $attendance_id,
-                            $content,
-                            $start_date,
-                            $duration
-                        );
-
-                        $affected_rows = $thematic->thematic_advance_save();
-
-                        if ($affected_rows) {
-                            // get last done thematic advance before move thematic list
-                            $last_done_thematic_advance = $thematic->get_last_done_thematic_advance();
-                            // update done advances with de current thematic list
-                            if (!empty($last_done_thematic_advance)) {
-                                $thematic->update_done_thematic_advances($last_done_thematic_advance);
-                            }
-                        }
-                    }
+                $data['action'] = $_REQUEST['action'];
+                $data['thematic_id'] = $_REQUEST['thematic_id'];
+                $data['attendance_select'] = $attendance_select;
+                if (isset($_REQUEST['thematic_advance_id'])) {
+                    $data['thematic_advance_id'] = $_REQUEST['thematic_advance_id'];
+                    $thematic_advance_data = $thematic->get_thematic_advance_list($_REQUEST['thematic_advance_id']);
+                    $data['thematic_advance_data'] = $thematic_advance_data;
                 }
                 break;
             default:

Some files were not shown because too many files changed in this diff