Removed: twitter, google, dropbox, facebook, owncloud, modernizr from JavaScript

This commit is contained in:
djmaze 2020-03-11 12:55:03 +01:00
parent e8d38a6870
commit 4468d5bd22
60 changed files with 7 additions and 4152 deletions

View file

@ -1,28 +0,0 @@
************************************************************************
*
* ownCloud/Nextcloud - RainLoop Webmail package
*
* @author RainLoop Team
* @copyright 2019 RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*
************************************************************************
REQUIREMENTS:
- ownCloud version 6 or higher
or
- Nextcloud version 10 or higher
INSTALL:
- Unpack the RainLoop Webmail application package in the apps directory of your ownCloud or Nextcloud instance
- Make sure the rights are appropriately set
CONFIGURATION:
- ownCloud:
1) In the Apps > Enable 'RainLoop' plugin
2) In the Settings > Personal > Type your email server login and password
- Nextcloud:
1) In the Apps > Enable 'RainLoop' plugin after checking 'Enable experimental apps'
2) In the Settings > Personal > Type your email server login and password

View file

@ -1 +0,0 @@
0.0

View file

@ -1,18 +0,0 @@
<?php
/**
* ownCloud - RainLoop mail plugin
*
* @author RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*/
OCP\User::checkAdminUser();
OCP\Util::addScript('rainloop', 'admin');
$oTemplate = new OCP\Template('rainloop', 'admin-local');
$oTemplate->assign('rainloop-admin-panel-link', OC_RainLoop_Helper::getAppUrl().'?admin');
$oTemplate->assign('rainloop-autologin', OCP\Config::getAppValue('rainloop', 'rainloop-autologin', false));
return $oTemplate->fetchPage();

View file

@ -1,35 +0,0 @@
<?php
/**
* ownCloud - RainLoop mail plugin
*
* @author RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*/
OCP\JSON::checkAdminUser();
OCP\JSON::checkAppEnabled('rainloop');
OCP\JSON::callCheck();
$sUrl = '';
$sPath = '';
$bAutologin = false;
if (isset($_POST['appname']) && 'rainloop' === $_POST['appname'])
{
OCP\Config::setAppValue('rainloop', 'rainloop-autologin', isset($_POST['rainloop-autologin']) ?
'1' === $_POST['rainloop-autologin'] : false);
$bAutologin = OCP\Config::getAppValue('rainloop', 'rainloop-autologin', false);
}
else
{
sleep(1);
OC_JSON::error(array('Message' => 'Invalid Argument(s)'));
return false;
}
sleep(1);
OCP\JSON::success(array('Message' => 'Saved successfully'));
return true;

View file

@ -1,46 +0,0 @@
<?php
/**
* ownCloud - RainLoop mail plugin
*
* @author RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*/
OCP\JSON::checkLoggedIn();
OCP\JSON::checkAppEnabled('rainloop');
OCP\JSON::callCheck();
$sEmail = '';
$sLogin = '';
if (isset($_POST['appname'], $_POST['rainloop-password'], $_POST['rainloop-email']) && 'rainloop' === $_POST['appname'])
{
$sUser = OCP\User::getUser();
$sPostEmail = $_POST['rainloop-email'];
OCP\Config::setUserValue($sUser, 'rainloop', 'rainloop-email', $sPostEmail);
$sPass = $_POST['rainloop-password'];
if ('******' !== $sPass && '' !== $sPass)
{
include_once OC_App::getAppPath('rainloop').'/lib/RainLoopHelper.php';
OCP\Config::setUserValue($sUser, 'rainloop', 'rainloop-password',
OC_RainLoop_Helper::encodePassword($sPass, md5($sPostEmail)));
}
$sEmail = OCP\Config::getUserValue($sUser, 'rainloop', 'rainloop-email', '');
}
else
{
sleep(1);
OC_JSON::error(array('Message' => 'Invalid argument(s)', 'Email' => $sEmail));
return false;
}
sleep(1);
OCP\JSON::success(array('Message' => 'Saved successfully', 'Email' => $sEmail));
return true;

View file

@ -1,36 +0,0 @@
<?php
OCP\User::checkLoggedIn();
if (@file_exists(__DIR__.'/app/index.php'))
{
include_once OC_App::getAppPath('rainloop').'/lib/RainLoopHelper.php';
OC_RainLoop_Helper::regRainLoopDataFunction();
if (isset($_GET['OwnCloudAuth']))
{
$sEmail = '';
$sEncodedPassword = '';
$sUser = OCP\User::getUser();
if (OCP\Config::getAppValue('rainloop', 'rainloop-autologin', false))
{
$sEmail = $sUser;
$sEncodedPassword = OCP\Config::getUserValue($sUser, 'rainloop', 'rainloop-autologin-password', '');
}
else
{
$sEmail = OCP\Config::getUserValue($sUser, 'rainloop', 'rainloop-email', '');
$sEncodedPassword = OCP\Config::getUserValue($sUser, 'rainloop', 'rainloop-password', '');
}
$sDecodedPassword = OC_RainLoop_Helper::decodePassword($sEncodedPassword, md5($sEmail));
$_ENV['___rainloop_owncloud_email'] = $sEmail;
$_ENV['___rainloop_owncloud_password'] = $sDecodedPassword;
}
include __DIR__.'/app/index.php';
}

View file

@ -1,33 +0,0 @@
<?php
/**
* ownCloud - RainLoop mail plugin
*
* @author RainLoop Team
*
* https://github.com/RainLoop/owncloud
*/
OC::$CLASSPATH['OC_RainLoop_Helper'] = OC_App::getAppPath('rainloop') . '/lib/RainLoopHelper.php';
OCP\App::registerAdmin('rainloop', 'admin');
OCP\App::registerPersonal('rainloop', 'personal');
if (OCP\Config::getAppValue('rainloop', 'rainloop-autologin', false))
{
OCP\Util::connectHook('OC_User', 'post_login', 'OC_RainLoop_Helper', 'login');
OCP\Util::connectHook('OC_User', 'post_setPassword', 'OC_RainLoop_Helper', 'changePassword');
}
OCP\Util::connectHook('OC_User', 'logout', 'OC_RainLoop_Helper', 'logout');
OCP\Util::addScript('rainloop', 'rainloop');
OCP\App::addNavigationEntry(array(
'id' => 'rainloop_index',
'order' => 10,
'href' => OCP\Util::linkToRoute('rainloop_index'),
'icon' => OCP\Util::imagePath('rainloop', 'mail.png'),
'name' => 'Email'
));

View file

@ -1,20 +0,0 @@
<?xml version="1.0"?>
<info xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
<id>rainloop</id>
<name>RainLoop</name>
<summary>RainLoop Webmail</summary>
<description>Simple, modern and fast web-based email client.</description>
<version>0.0</version>
<licence></licence>
<author>RainLoop Team</author>
<require>6.0</require>
<ocsid>165254</ocsid>
<dependencies>
<php min-version="5.4" />
<owncloud min-version="6" max-version="9.2" />
<nextcloud min-version="8" max-version="11" />
</dependencies>
<category>tools</category>
<website>https://www.rainloop.net/</website>
<bugs>https://github.com/RainLoop/rainloop-webmail/issues</bugs>
</info>

View file

@ -1,13 +0,0 @@
<?php
$this->create('rainloop_index', '/')
->actionInclude('rainloop/index.php');
$this->create('rainloop_app', '/app/')
->actionInclude('rainloop/app.php');
$this->create('rainloop_ajax_personal', 'ajax/personal.php')
->actionInclude('rainloop/ajax/personal.php');
$this->create('rainloop_ajax_admin', 'ajax/admin.php')
->actionInclude('rainloop/ajax/admin.php');

View file

@ -1,6 +0,0 @@
/*
Empty style sheet!
Only needed to give you the opportunity to theme the owncloud part
of the rainloop app with the theming system integrated in ownCoud
if the rainloop app is activated.
*/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 832 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 478 B

View file

@ -1,26 +0,0 @@
<?php
/**
* ownCloud - RainLoop mail plugin
*
* @author RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*/
OCP\User::checkLoggedIn();
OCP\App::checkAppEnabled('rainloop');
OCP\App::setActiveNavigationEntry('rainloop_index');
// Load the empty file ../css/style.css, that's needed to allow theming of
// the ownCloud header and navigation if rainloop is the active app.
OCP\Util::addStyle('rainloop', 'style');
include_once OC_App::getAppPath('rainloop').'/lib/RainLoopHelper.php';
$sUrl = OC_RainLoop_Helper::normalizeUrl(OC_RainLoop_Helper::getAppUrl());
$oTemplate = new OCP\Template('rainloop', 'index', 'user');
$oTemplate->assign('rainloop-iframe-url', OC_RainLoop_Helper::normalizeUrl($sUrl).'?OwnCloudAuth');
$oTemplate->printpage();

View file

@ -1,12 +0,0 @@
/**
* ownCloud - RainLoop mail plugin
*
* @author RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*/
$(function() {
RainLoopFormHelper('#mail-rainloop-admin-form', 'admin.php');
});

View file

@ -1,12 +0,0 @@
/**
* ownCloud - RainLoop mail plugin
*
* @author RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*/
$(function() {
RainLoopFormHelper('#mail-rainloop-personal-form', 'personal.php');
});

View file

@ -1,76 +0,0 @@
function RainLoopFormHelper(sID, sAjaxFile, fCallback)
{
try
{
var
oForm = $(sID),
oSubmit = $('#rainloop-save-button', oForm),
sSubmitValue = oSubmit.val(),
oDesc = oForm.find('.rainloop-result-desc')
;
oSubmit.click(function (oEvent) {
var oDefAjax = null;
oEvent.preventDefault();
oForm
.addClass('rainloop-ajax')
.removeClass('rainloop-error')
.removeClass('rainloop-success')
;
oDesc.text('');
oSubmit.val('...');
oDefAjax = $.ajax({
'type': 'POST',
'async': true,
'url': OC.filePath('rainloop', 'ajax', sAjaxFile),
'data': oForm.serialize(),
'dataType': 'json',
'global': true
});
oDefAjax.always(function (oData) {
var bResult = false;
oForm.removeClass('rainloop-ajax');
oSubmit.val(sSubmitValue);
if (oData)
{
bResult = 'success' === oData['status'];
if (oData['Message'])
{
oDesc.text(oData['Message']);
}
}
if (bResult)
{
oForm.addClass('rainloop-success');
}
else
{
oForm.addClass('rainloop-error');
if ('' === oDesc.text())
{
oDesc.text('Error');
}
}
if (fCallback)
{
fCallback(bResult, oData);
}
});
return false;
});
}
catch(e) {}
}

View file

@ -1,26 +0,0 @@
$(function (window, document) {
var
buffer = 5,
ifr = document.getElementById('rliframe')
;
function pageY(elem) {
return elem.offsetParent ? (elem.offsetTop + pageY(elem.offsetParent)) : elem.offsetTop;
}
function resizeIframe() {
var height = document.documentElement.clientHeight;
height -= pageY(ifr) + buffer;
height = (height < 0) ? 0 : height;
ifr.style.height = height + 'px';
}
if (ifr)
{
ifr.onload = resizeIframe;
window.onresize = resizeIframe;
}
}(window, document));

View file

@ -1,352 +0,0 @@
<?php
class OC_RainLoop_Helper
{
/**
* @return string
*/
public static function getAppUrl()
{
if (class_exists('\\OCP\\Util'))
{
return OCP\Util::linkToRoute('rainloop_app');
}
$sRequestUri = empty($_SERVER['REQUEST_URI']) ? '': trim($_SERVER['REQUEST_URI']);
$sRequestUri = preg_replace('/index.php\/.+$/', 'index.php/', $sRequestUri);
$sRequestUri = $sRequestUri.'apps/rainloop/app/';
return '/'.ltrim($sRequestUri, '/\\');
}
/**
* @param string $sPath
* @param string $sEmail
* @param string $sPassword
*
* @return string
*/
public static function getSsoHash($sPath, $sEmail, $sPassword)
{
$SsoHash = '';
$sPath = rtrim(trim($sPath), '\\/').'/index.php';
if (file_exists($sPath))
{
self::regRainLoopDataFunction();
$_ENV['RAINLOOP_INCLUDE_AS_API'] = true;
include $sPath;
if (class_exists('\\RainLoop\\Api'))
{
$SsoHash = \RainLoop\Api::GetUserSsoHash($sEmail, $sPassword);
}
}
return $SsoHash;
}
/**
* @param string $sUrl
*
* @return string
*/
public static function normalizeUrl($sUrl)
{
$sUrl = rtrim(trim($sUrl), '/\\');
if ('.php' !== strtolower(substr($sUrl, -4)))
{
$sUrl .= '/';
}
return $sUrl;
}
/**
* @return boolean
*/
public static function mcryptSupported()
{
return function_exists('mcrypt_encrypt') &&
function_exists('mcrypt_decrypt') &&
defined('MCRYPT_RIJNDAEL_256') &&
defined('MCRYPT_MODE_ECB');
}
/**
* @return string
*/
public static function openSslSupportedMethod()
{
$method = 'AES-256-CBC';
return function_exists('openssl_encrypt') &&
function_exists('openssl_decrypt') &&
function_exists('openssl_random_pseudo_bytes') &&
function_exists('openssl_cipher_iv_length') &&
function_exists('openssl_get_cipher_methods') &&
defined('OPENSSL_RAW_DATA') && defined('OPENSSL_ZERO_PADDING') &&
in_array($method, openssl_get_cipher_methods()) ? $method : '';
}
/**
* @param string $sMethod
* @param string $sPassword
* @param string $sSalt
*
* @return string
*/
public static function encodePasswordSsl($sMethod, $sPassword, $sSalt)
{
$sData = base64_encode($sPassword);
$iv = @openssl_random_pseudo_bytes(openssl_cipher_iv_length($sMethod));
$r = @openssl_encrypt($sData, $sMethod, md5($sSalt), OPENSSL_RAW_DATA, $iv);
return @base64_encode(base64_encode($r).'|'.base64_encode($iv));
}
/**
* @param string $sMethod
* @param string $sPassword
* @param string $sSalt
*
* @return string
*/
public static function decodePasswordSsl($sMethod, $sPassword, $sSalt)
{
$sLine = base64_decode(trim($sPassword));
$aParts = explode('|', $sLine, 2);
if (is_array($aParts) && !empty($aParts[0]) && !empty($aParts[1])) {
$sData = @base64_decode($aParts[0]);
$iv = @base64_decode($aParts[1]);
return @base64_decode(trim(
@openssl_decrypt($sData, $sMethod, md5($sSalt), OPENSSL_RAW_DATA, $iv)
));
}
return '';
}
/**
* @param string $sPassword
* @param string $sSalt
*
* @return string
*/
public static function encodePassword($sPassword, $sSalt)
{
$method = self::openSslSupportedMethod();
if ($method)
{
return self::encodePasswordSsl($method, $sPassword, $sSalt);
}
else if (self::mcryptSupported())
{
return @trim(base64_encode(
@mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($sSalt), base64_encode($sPassword), MCRYPT_MODE_ECB)
));
}
return @trim(base64_encode($sPassword));
}
/**
* @param string $sPassword
* @param string $sSalt
*
* @return string
*/
public static function decodePassword($sPassword, $sSalt)
{
$method = self::openSslSupportedMethod();
if ($method)
{
return self::decodePasswordSsl($method, $sPassword, $sSalt);
}
else if (self::mcryptSupported())
{
return @base64_decode(trim(
@mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($sSalt), base64_decode(trim($sPassword)), MCRYPT_MODE_ECB)
));
}
return @base64_decode(trim($sPassword));
}
/**
* @param array $aParams
*
* @return boolean
*/
public static function login($aParams)
{
if (isset($aParams['uid'], $aParams['password']))
{
$sUser = $aParams['uid'];
$sEmail = $sUser;
$sPassword = $aParams['password'];
return OCP\Config::setUserValue($sUser, 'rainloop', 'rainloop-autologin-password',
self::encodePassword($sPassword, md5($sEmail)));
}
return false;
}
public static function logout()
{
OCP\Config::setUserValue(
OCP\User::getUser(), 'rainloop', 'rainloop-autologin-password', '');
$sApiPath = __DIR__.'/../app/index.php';
if (file_exists($sApiPath))
{
self::regRainLoopDataFunction();
$_ENV['RAINLOOP_INCLUDE_AS_API'] = true;
include $sApiPath;
if (class_exists('\\RainLoop\\Api'))
{
\RainLoop\Api::LogoutCurrentLogginedUser();
}
}
return true;
}
public static function changePassword($aParams)
{
if (isset($aParams['uid'], $aParams['password']))
{
$sUser = $aParams['uid'];
$sEmail = $sUser;
$sPassword = $aParams['password'];
OCP\Util::writeLog('rainloop', 'rainloop|login: Setting new RainLoop password for '.$sEmail, OCP\Util::DEBUG);
OCP\Config::setUserValue($sUser, 'rainloop', 'rainloop-autologin-password',
self::encodePassword($sPassword, md5($sEmail)));
OCP\Config::setUserValue($sUser, 'rainloop', 'rainloop-password',
self::encodePassword($sPassword, md5($sEmail)));
return true;
}
return false;
}
public static function regRainLoopDataFunction()
{
if (!@function_exists('__get_custom_data_full_path'))
{
$_ENV['RAINLOOP_OWNCLOUD'] = true;
function __get_custom_data_full_path()
{
$sData = __DIR__.'/../../data/';
if (class_exists('OC_Config'))
{
$sData = rtrim(trim(OC_Config::getValue('datadirectory', '')), '\\/').'/';
}
else if (class_exists('OC'))
{
$sData = rtrim(trim(
OC::$server->getSystemConfig()->getValue(
'datadirectory',
isset(\OC::$SERVERROOT) ? \OC::$SERVERROOT.'/data' : ''
)
), '\\/').'/';
}
return @is_dir($sData) ? $sData.'rainloop-storage' : '';
}
}
}
public static function mimeContentType($filename) {
$mime_types = array(
'woff' => 'application/font-woff',
'txt' => 'text/plain',
'htm' => 'text/html',
'html' => 'text/html',
'php' => 'text/html',
'css' => 'text/css',
'js' => 'application/javascript',
'json' => 'application/json',
'xml' => 'application/xml',
'swf' => 'application/x-shockwave-flash',
'flv' => 'video/x-flv',
// images
'png' => 'image/png',
'jpe' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg',
'gif' => 'image/gif',
'bmp' => 'image/bmp',
'ico' => 'image/vnd.microsoft.icon',
'tiff' => 'image/tiff',
'tif' => 'image/tiff',
'svg' => 'image/svg+xml',
'svgz' => 'image/svg+xml',
// archives
'zip' => 'application/zip',
'rar' => 'application/x-rar-compressed',
'exe' => 'application/x-msdownload',
'msi' => 'application/x-msdownload',
'cab' => 'application/vnd.ms-cab-compressed',
// audio/video
'mp3' => 'audio/mpeg',
'qt' => 'video/quicktime',
'mov' => 'video/quicktime',
// adobe
'pdf' => 'application/pdf',
'psd' => 'image/vnd.adobe.photoshop',
'ai' => 'application/postscript',
'eps' => 'application/postscript',
'ps' => 'application/postscript',
// ms office
'doc' => 'application/msword',
'rtf' => 'application/rtf',
'xls' => 'application/vnd.ms-excel',
'ppt' => 'application/vnd.ms-powerpoint',
// open office
'odt' => 'application/vnd.oasis.opendocument.text',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
);
if (0 < strpos($filename, '.'))
{
$ext = strtolower(array_pop(explode('.',$filename)));
if (array_key_exists($ext, $mime_types))
{
return $mime_types[$ext];
}
else if (function_exists('finfo_open'))
{
$finfo = finfo_open(FILEINFO_MIME);
$mimetype = finfo_file($finfo, $filename);
finfo_close($finfo);
return $mimetype;
}
}
return 'application/octet-stream';
}
}

View file

@ -1,33 +0,0 @@
<?php
/**
* ownCloud - RainLoop mail plugin
*
* @author RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*/
OCP\User::checkLoggedIn();
OCP\App::checkAppEnabled('rainloop');
OCP\Util::addScript('rainloop', 'personal');
if (OCP\Config::getAppValue('rainloop', 'rainloop-autologin', false))
{
$oTemplate = new OCP\Template('rainloop', 'empty');
}
else
{
$sUser = OCP\User::getUser();
$oTemplate = new OCP\Template('rainloop', 'personal');
$sEmail = OCP\Config::getUserValue($sUser, 'rainloop', 'rainloop-email', '');
$sPass = OCP\Config::getUserValue($sUser, 'rainloop', 'rainloop-password', '');
$oTemplate->assign('rainloop-email', $sEmail);
$oTemplate->assign('rainloop-password', 0 === strlen($sPass) && 0 === strlen($sEmail) ? '' : '******');
}
return $oTemplate->fetchPage();

View file

@ -1,29 +0,0 @@
<div class="section">
<form id="mail-rainloop-admin-form" action="#" method="post">
<input type="hidden" name="requesttoken" value="<?php echo $_['requesttoken'] ?>" id="requesttoken">
<input type="hidden" name="appname" value="rainloop">
<fieldset class="personalblock">
<h2><?php p($l->t('RainLoop Webmail')); ?></h2>
<br />
<?php if ($_['rainloop-admin-panel-link']): ?>
<p>
<a href="<?php echo $_['rainloop-admin-panel-link'] ?>" target="_blank" style="text-decoration: underline">
<?php p($l->t('Go to RainLoop Webmail admin panel')); ?>
</a>
</p>
<br />
<?php endif; ?>
<p>
<input type="checkbox" id="rainloop-autologin" id="rainloop-autologin" name="rainloop-autologin" value="1" <?php if ($_['rainloop-autologin']): ?>checked="checked"<?php endif; ?> />
<label for="rainloop-autologin">
<?php p($l->t('Automatically login with ownCloud user credentials')); ?>
</label>
<br />
<br />
<input type="button" id="rainloop-save-button" name="rainloop-save-button" value="<?php p($l->t('Save')); ?>" />
&nbsp;&nbsp;<span class="rainloop-result-desc"></span>
</p>
</fieldset>
</form>
</div>

View file

@ -1 +0,0 @@
<!-- empty -->

View file

@ -1,3 +0,0 @@
<div style="margin: 20px">
<?php p($l->t('RainLoop Webmail is not configured yet.')); ?>
</div>

View file

@ -1,3 +0,0 @@
<div style="box-sizing: border-box; width: 100%; height: 100%; padding: 0px; margin: 0px; background-color: #383c43; position: relative; overflow: hidden;"
><iframe id="rliframe" style="border: none; width: 100%; height: 100%; position: absolute; top: 0px; left: 0px; right: 0px; bottom: 0px;" tabindex="-1" frameborder="0"
src="<?php echo $_['rainloop-iframe-url']; ?>"></iframe></div><?php OCP\Util::addScript('rainloop', 'resize');

View file

@ -1,20 +0,0 @@
<div class="section">
<form id="mail-rainloop-personal-form" action="#" method="post">
<input type="hidden" name="requesttoken" value="<?php echo $_['requesttoken'] ?>" id="requesttoken">
<input type="hidden" name="appname" value="rainloop">
<fieldset class="personalblock">
<h2><?php p($l->t('RainLoop Webmail')); ?></h2>
<p>
<input type="text" id="rainloop-email" name="rainloop-email"
value="<?php echo $_['rainloop-email']; ?>" placeholder="<?php p($l->t('Email')); ?>" />
<input type="password" id="rainloop-password" name="rainloop-password" autocomplete="current-password"
value="<?php echo $_['rainloop-password']; ?>" placeholder="<?php p($l->t('Password')); ?>" />
<input type="button" id="rainloop-save-button" name="rainloop-save-button" value="<?php p($l->t('Save')); ?>" />
&nbsp;&nbsp;<span class="rainloop-result-desc"></span>
</p>
</fieldset>
</form>
</div>

View file

@ -26,7 +26,6 @@ import * as Settings from 'Storage/Settings';
import LanguageStore from 'Stores/Language';
import ThemeStore from 'Stores/Theme';
import SocialStore from 'Stores/Social';
import { routeOff, setHash } from 'Knoin/Knoin';
import { AbstractBoot } from 'Knoin/AbstractBoot';
@ -38,7 +37,6 @@ class AbstractApp extends AbstractBoot {
constructor() {
super();
this.googlePreviewSupportedCache = null;
this.isLocalAutocomplete = true;
this.iframe = null;
this.lastErrorTime = 0;
@ -140,18 +138,6 @@ class AbstractApp extends AbstractBoot {
return true;
}
/**
* @returns {boolean}
*/
googlePreviewSupported() {
if (null === this.googlePreviewSupportedCache) {
this.googlePreviewSupportedCache =
!!Settings.settingsGet('AllowGoogleSocial') && !!Settings.settingsGet('AllowGoogleSocialPreview');
}
return this.googlePreviewSupportedCache;
}
/**
* @param {string} title
*/
@ -345,7 +331,6 @@ class AbstractApp extends AbstractBoot {
LanguageStore.populate();
ThemeStore.populate();
SocialStore.populate();
}
}

View file

@ -56,17 +56,13 @@ import {
mailBox,
root,
openPgpWorkerJs,
openPgpJs,
socialGoogle,
socialTwitter,
socialFacebook
openPgpJs
} from 'Common/Links';
import * as Events from 'Common/Events';
import { getNotification, i18n } from 'Common/Translator';
import SocialStore from 'Stores/Social';
import AppStore from 'Stores/User/App';
import SettingsStore from 'Stores/User/Settings';
import NotificationStore from 'Stores/User/Notification';
@ -160,8 +156,6 @@ class AppUser extends AbstractApp {
.removeAttr('style');
}, Magics.Time1s);
}
this.socialUsers = _.bind(this.socialUsers, this);
}
remote() {
@ -854,72 +848,6 @@ class AppUser extends AbstractApp {
}
}
googleConnect() {
window.open(
socialGoogle(),
'Google',
'left=200,top=100,width=650,height=600,menubar=no,status=no,resizable=yes,scrollbars=yes'
);
}
twitterConnect() {
window.open(
socialTwitter(),
'Twitter',
'left=200,top=100,width=650,height=350,menubar=no,status=no,resizable=yes,scrollbars=yes'
);
}
facebookConnect() {
window.open(
socialFacebook(),
'Facebook',
'left=200,top=100,width=650,height=335,menubar=no,status=no,resizable=yes,scrollbars=yes'
);
}
/**
* @param {boolean=} fireAllActions = false
*/
socialUsers(fireAllActions = false) {
if (true === fireAllActions) {
SocialStore.google.loading(true);
SocialStore.facebook.loading(true);
SocialStore.twitter.loading(true);
}
Remote.socialUsers((result, data) => {
if (StorageResultType.Success === result && data && data.Result) {
SocialStore.google.userName(data.Result.Google || '');
SocialStore.facebook.userName(data.Result.Facebook || '');
SocialStore.twitter.userName(data.Result.Twitter || '');
} else {
SocialStore.google.userName('');
SocialStore.facebook.userName('');
SocialStore.twitter.userName('');
}
SocialStore.google.loading(false);
SocialStore.facebook.loading(false);
SocialStore.twitter.loading(false);
});
}
googleDisconnect() {
SocialStore.google.loading(true);
Remote.googleDisconnect(this.socialUsers);
}
facebookDisconnect() {
SocialStore.facebook.loading(true);
Remote.facebookDisconnect(this.socialUsers);
}
twitterDisconnect() {
SocialStore.twitter.loading(true);
Remote.twitterDisconnect(this.socialUsers);
}
/**
* @param {string} query
* @param {Function} autocompleteCallback
@ -1198,10 +1126,7 @@ class AppUser extends AbstractApp {
let contactsSyncInterval = pInt(Settings.settingsGet('ContactsSyncInterval'));
const jsHash = Settings.appSettingsGet('jsHash'),
startupUrl = pString(Settings.settingsGet('StartupUrl')),
allowGoogle = Settings.settingsGet('AllowGoogleSocial'),
allowFacebook = Settings.settingsGet('AllowFacebookSocial'),
allowTwitter = Settings.settingsGet('AllowTwitterSocial');
startupUrl = pString(Settings.settingsGet('StartupUrl'));
if (progressJs) {
progressJs.set(90);
@ -1276,10 +1201,6 @@ class AppUser extends AbstractApp {
// false ? AboutUserScreen : null
]);
if (allowGoogle || allowFacebook || allowTwitter) {
this.socialUsers(true);
}
Events.sub('interval.2m', () => this.folderInformation(getFolderInboxName()));
Events.sub('interval.3m', () => {
const sF = FolderStore.currentFolderFullNameRaw();
@ -1356,27 +1277,6 @@ class AppUser extends AbstractApp {
this.bootstartLoginScreen();
}
if (allowGoogle) {
window['rl_' + jsHash + '_google_service'] = () => {
SocialStore.google.loading(true);
this.socialUsers();
};
}
if (allowFacebook) {
window['rl_' + jsHash + '_facebook_service'] = () => {
SocialStore.facebook.loading(true);
this.socialUsers();
};
}
if (allowTwitter) {
window['rl_' + jsHash + '_twitter_service'] = () => {
SocialStore.twitter.loading(true);
this.socialUsers();
};
}
Events.sub('interval.1m', () => momentReload());
runHook('rl-start-screens');

View file

@ -255,35 +255,6 @@ export function exportContactsCsv() {
return SERVER_PREFIX + '/Raw/' + SUB_QUERY_PREFIX + '/' + AUTH_PREFIX + '/ContactsCsv/';
}
/**
* @param {boolean} xauth = false
* @returns {string}
*/
export function socialGoogle(xauth = false) {
return (
SERVER_PREFIX +
'SocialGoogle' +
('' !== AUTH_PREFIX ? '/' + SUB_QUERY_PREFIX + '/' + AUTH_PREFIX + '/' : '') +
(xauth ? '&xauth=1' : '')
);
}
/**
* @returns {string}
*/
export function socialTwitter() {
return SERVER_PREFIX + 'SocialTwitter' + ('' !== AUTH_PREFIX ? '/' + SUB_QUERY_PREFIX + '/' + AUTH_PREFIX + '/' : '');
}
/**
* @returns {string}
*/
export function socialFacebook() {
return (
SERVER_PREFIX + 'SocialFacebook' + ('' !== AUTH_PREFIX ? '/' + SUB_QUERY_PREFIX + '/' + AUTH_PREFIX + '/' : '')
);
}
/**
* @param {string} path
* @returns {string}

View file

@ -909,55 +909,6 @@ class RemoteUserAjax extends AbstractAjaxRemote {
clearUserBackground(fCallback) {
this.defaultRequest(fCallback, 'ClearUserBackground');
}
/**
* @param {?Function} fCallback
*/
facebookUser(fCallback) {
this.defaultRequest(fCallback, 'SocialFacebookUserInformation');
}
/**
* @param {?Function} fCallback
*/
facebookDisconnect(fCallback) {
this.defaultRequest(fCallback, 'SocialFacebookDisconnect');
}
/**
* @param {?Function} fCallback
*/
twitterUser(fCallback) {
this.defaultRequest(fCallback, 'SocialTwitterUserInformation');
}
/**
* @param {?Function} fCallback
*/
twitterDisconnect(fCallback) {
this.defaultRequest(fCallback, 'SocialTwitterDisconnect');
}
/**
* @param {?Function} fCallback
*/
googleUser(fCallback) {
this.defaultRequest(fCallback, 'SocialGoogleUserInformation');
}
/**
* @param {?Function} fCallback
*/
googleDisconnect(fCallback) {
this.defaultRequest(fCallback, 'SocialGoogleDisconnect');
}
/**
* @param {?Function} fCallback
*/
socialUsers(fCallback) {
this.defaultRequest(fCallback, 'SocialUsers');
}
}
export default new RemoteUserAjax();

View file

@ -8,7 +8,6 @@ import { DomainsAdminSettings } from 'Settings/Admin/Domains';
import { LoginAdminSettings } from 'Settings/Admin/Login';
import { ContactsAdminSettings } from 'Settings/Admin/Contacts';
import { SecurityAdminSettings } from 'Settings/Admin/Security';
import { SocialAdminSettings } from 'Settings/Admin/Social';
import { PluginsAdminSettings } from 'Settings/Admin/Plugins';
import { PackagesAdminSettings } from 'Settings/Admin/Packages';
import { AboutAdminSettings } from 'Settings/Admin/About';
@ -57,13 +56,6 @@ class SettingsAdminScreen extends AbstractSettingsScreen {
addSettingsViewModel(SecurityAdminSettings, 'AdminSettingsSecurity', 'TABS_LABELS/LABEL_SECURITY_NAME', 'security');
addSettingsViewModel(
SocialAdminSettings,
'AdminSettingsSocial',
'TABS_LABELS/LABEL_INTEGRATION_NAME',
'integrations'
);
addSettingsViewModel(PluginsAdminSettings, 'AdminSettingsPlugins', 'TABS_LABELS/LABEL_PLUGINS_NAME', 'plugins');
addSettingsViewModel(PackagesAdminSettings, 'AdminSettingsPackages', 'TABS_LABELS/LABEL_PACKAGES_NAME', 'packages');

View file

@ -16,7 +16,6 @@ import { ContactsUserSettings } from 'Settings/User/Contacts';
import { AccountsUserSettings } from 'Settings/User/Accounts';
import { FiltersUserSettings } from 'Settings/User/Filters';
import { SecurityUserSettings } from 'Settings/User/Security';
import { SocialUserSettings } from 'Settings/User/Social';
import { ChangePasswordUserSettings } from 'Settings/User/ChangePassword';
import { TemplatesUserSettings } from 'Settings/User/Templates';
import { FoldersUserSettings } from 'Settings/User/Folders';
@ -80,15 +79,6 @@ class SettingsUserScreen extends AbstractSettingsScreen {
addSettingsViewModel(SecurityUserSettings, 'SettingsSecurity', 'SETTINGS_LABELS/LABEL_SECURITY_NAME', 'security');
}
if (
AccountStore.isRootAccount() &&
((Settings.settingsGet('AllowGoogleSocial') && Settings.settingsGet('AllowGoogleSocialAuth')) ||
Settings.settingsGet('AllowFacebookSocial') ||
Settings.settingsGet('AllowTwitterSocial'))
) {
addSettingsViewModel(SocialUserSettings, 'SettingsSocial', 'SETTINGS_LABELS/LABEL_SOCIAL_NAME', 'social');
}
if (Settings.settingsGet('ChangePasswordIsAllowed')) {
addSettingsViewModel(
ChangePasswordUserSettings,

View file

@ -1,105 +0,0 @@
import _ from '_';
import ko from 'ko';
import { SaveSettingsStep, Magics } from 'Common/Enums';
import { settingsSaveHelperSimpleFunction, trim, boolToAjax } from 'Common/Utils';
import SocialStore from 'Stores/Social';
import Remote from 'Remote/Admin/Ajax';
class SocialAdminSettings {
constructor() {
this.googleEnable = SocialStore.google.enabled;
this.googleEnableAuth = SocialStore.google.capa.auth;
this.googleEnableAuthGmail = SocialStore.google.capa.authGmail;
this.googleEnableDrive = SocialStore.google.capa.drive;
this.googleEnablePreview = SocialStore.google.capa.preview;
this.googleEnableRequireClientSettings = SocialStore.google.require.clientSettings;
this.googleEnableRequireApiKey = SocialStore.google.require.apiKeySettings;
this.googleClientID = SocialStore.google.clientID;
this.googleClientSecret = SocialStore.google.clientSecret;
this.googleApiKey = SocialStore.google.apiKey;
this.googleTrigger1 = ko.observable(SaveSettingsStep.Idle);
this.googleTrigger2 = ko.observable(SaveSettingsStep.Idle);
this.googleTrigger3 = ko.observable(SaveSettingsStep.Idle);
this.facebookSupported = SocialStore.facebook.supported;
this.facebookEnable = SocialStore.facebook.enabled;
this.facebookAppID = SocialStore.facebook.appID;
this.facebookAppSecret = SocialStore.facebook.appSecret;
this.facebookTrigger1 = ko.observable(SaveSettingsStep.Idle);
this.facebookTrigger2 = ko.observable(SaveSettingsStep.Idle);
this.twitterEnable = SocialStore.twitter.enabled;
this.twitterConsumerKey = SocialStore.twitter.consumerKey;
this.twitterConsumerSecret = SocialStore.twitter.consumerSecret;
this.twitterTrigger1 = ko.observable(SaveSettingsStep.Idle);
this.twitterTrigger2 = ko.observable(SaveSettingsStep.Idle);
this.dropboxEnable = SocialStore.dropbox.enabled;
this.dropboxApiKey = SocialStore.dropbox.apiKey;
this.dropboxTrigger1 = ko.observable(SaveSettingsStep.Idle);
}
onBuild() {
_.delay(() => {
const f1 = settingsSaveHelperSimpleFunction(this.facebookTrigger1, this),
f2 = settingsSaveHelperSimpleFunction(this.facebookTrigger2, this),
f3 = settingsSaveHelperSimpleFunction(this.twitterTrigger1, this),
f4 = settingsSaveHelperSimpleFunction(this.twitterTrigger2, this),
f5 = settingsSaveHelperSimpleFunction(this.googleTrigger1, this),
f6 = settingsSaveHelperSimpleFunction(this.googleTrigger2, this),
f7 = settingsSaveHelperSimpleFunction(this.googleTrigger3, this),
f8 = settingsSaveHelperSimpleFunction(this.dropboxTrigger1, this);
this.facebookEnable.subscribe((value) => {
if (this.facebookSupported()) {
Remote.saveAdminConfig(null, {
'FacebookEnable': boolToAjax(value)
});
}
});
this.facebookAppID.subscribe((value) => {
if (this.facebookSupported()) {
Remote.saveAdminConfig(f1, {
'FacebookAppID': trim(value)
});
}
});
this.facebookAppSecret.subscribe((value) => {
if (this.facebookSupported()) {
Remote.saveAdminConfig(f2, {
'FacebookAppSecret': trim(value)
});
}
});
this.twitterEnable.subscribe(Remote.saveAdminConfigHelper('TwitterEnable', boolToAjax));
this.twitterConsumerKey.subscribe(Remote.saveAdminConfigHelper('TwitterConsumerKey', trim, f3));
this.twitterConsumerSecret.subscribe(Remote.saveAdminConfigHelper('TwitterConsumerSecret', trim, f4));
this.googleEnable.subscribe(Remote.saveAdminConfigHelper('GoogleEnable', boolToAjax));
this.googleEnableAuth.subscribe(Remote.saveAdminConfigHelper('GoogleEnableAuth', boolToAjax));
this.googleEnableAuthGmail.subscribe(Remote.saveAdminConfigHelper('GoogleEnableAuthGmail', boolToAjax));
this.googleEnableDrive.subscribe(Remote.saveAdminConfigHelper('GoogleEnableDrive', boolToAjax));
this.googleEnablePreview.subscribe(Remote.saveAdminConfigHelper('GoogleEnablePreview', boolToAjax));
this.googleClientID.subscribe(Remote.saveAdminConfigHelper('GoogleClientID', trim, f5));
this.googleClientSecret.subscribe(Remote.saveAdminConfigHelper('GoogleClientSecret', trim, f6));
this.googleApiKey.subscribe(Remote.saveAdminConfigHelper('GoogleApiKey', trim, f7));
this.dropboxEnable.subscribe(Remote.saveAdminConfigHelper('DropboxEnable', boolToAjax));
this.dropboxApiKey.subscribe(Remote.saveAdminConfigHelper('DropboxApiKey', trim, f8));
}, Magics.Time50ms);
}
}
export { SocialAdminSettings, SocialAdminSettings as default };

View file

@ -1,69 +0,0 @@
import SocialStore from 'Stores/Social';
import { getApp } from 'Helper/Apps/User';
import { command } from 'Knoin/Knoin';
class SocialUserSettings {
constructor() {
this.googleEnable = SocialStore.google.enabled;
this.googleEnableAuth = SocialStore.google.capa.auth;
this.googleEnableAuthGmail = SocialStore.google.capa.authGmail;
this.googleEnableDrive = SocialStore.google.capa.drive;
this.googleEnablePreview = SocialStore.google.capa.preview;
this.googleActions = SocialStore.google.loading;
this.googleLoggined = SocialStore.google.loggined;
this.googleUserName = SocialStore.google.userName;
this.facebookEnable = SocialStore.facebook.enabled;
this.facebookActions = SocialStore.facebook.loading;
this.facebookLoggined = SocialStore.facebook.loggined;
this.facebookUserName = SocialStore.facebook.userName;
this.twitterEnable = SocialStore.twitter.enabled;
this.twitterActions = SocialStore.twitter.loading;
this.twitterLoggined = SocialStore.twitter.loggined;
this.twitterUserName = SocialStore.twitter.userName;
}
@command((self) => !self.googleLoggined() && !self.googleActions())
connectGoogleCommand() {
if (!this.googleLoggined()) {
getApp().googleConnect();
}
}
@command()
disconnectGoogleCommand() {
getApp().googleDisconnect();
}
@command((self) => !self.facebookLoggined() && !self.facebookActions())
connectFacebookCommand() {
if (!this.facebookLoggined()) {
getApp().facebookConnect();
}
}
@command()
disconnectFacebookCommand() {
getApp().facebookDisconnect();
}
@command((self) => !self.twitterLoggined() && !self.twitterActions())
connectTwitterCommand() {
if (!this.twitterLoggined()) {
getApp().twitterConnect();
}
}
@command()
disconnectTwitterCommand() {
getApp().twitterDisconnect();
}
}
export { SocialUserSettings, SocialUserSettings as default };

View file

@ -1,103 +0,0 @@
import window from 'window';
import ko from 'ko';
import $ from '$';
import * as Settings from 'Storage/Settings';
class SocialStore {
constructor() {
this.google = {};
this.twitter = {};
this.facebook = {};
this.dropbox = {};
// Google
this.google.enabled = ko.observable(false);
this.google.clientID = ko.observable('');
this.google.clientSecret = ko.observable('');
this.google.apiKey = ko.observable('');
this.google.loading = ko.observable(false);
this.google.userName = ko.observable('');
this.google.loggined = ko.computed(() => '' !== this.google.userName());
this.google.capa = {};
this.google.capa.auth = ko.observable(false);
this.google.capa.authGmail = ko.observable(false);
this.google.capa.drive = ko.observable(false);
this.google.capa.preview = ko.observable(false);
this.google.require = {};
this.google.require.clientSettings = ko.computed(
() =>
this.google.enabled() && (this.google.capa.auth() || this.google.capa.authGmail() || this.google.capa.drive())
);
this.google.require.apiKeySettings = ko.computed(() => this.google.enabled() && this.google.capa.drive());
// Facebook
this.facebook.enabled = ko.observable(false);
this.facebook.appID = ko.observable('');
this.facebook.appSecret = ko.observable('');
this.facebook.loading = ko.observable(false);
this.facebook.userName = ko.observable('');
this.facebook.supported = ko.observable(false);
this.facebook.loggined = ko.computed(() => '' !== this.facebook.userName());
// Twitter
this.twitter.enabled = ko.observable(false);
this.twitter.consumerKey = ko.observable('');
this.twitter.consumerSecret = ko.observable('');
this.twitter.loading = ko.observable(false);
this.twitter.userName = ko.observable('');
this.twitter.loggined = ko.computed(() => '' !== this.twitter.userName());
// Dropbox
this.dropbox.enabled = ko.observable(false);
this.dropbox.apiKey = ko.observable('');
}
populate() {
this.google.enabled(!!Settings.settingsGet('AllowGoogleSocial'));
this.google.clientID(Settings.settingsGet('GoogleClientID'));
this.google.clientSecret(Settings.settingsGet('GoogleClientSecret'));
this.google.apiKey(Settings.settingsGet('GoogleApiKey'));
this.google.capa.auth(!!Settings.settingsGet('AllowGoogleSocialAuth'));
this.google.capa.authGmail(!!Settings.settingsGet('AllowGoogleSocialAuthGmail'));
this.google.capa.drive(!!Settings.settingsGet('AllowGoogleSocialDrive'));
this.google.capa.preview(!!Settings.settingsGet('AllowGoogleSocialPreview'));
this.facebook.enabled(!!Settings.settingsGet('AllowFacebookSocial'));
this.facebook.appID(Settings.settingsGet('FacebookAppID'));
this.facebook.appSecret(Settings.settingsGet('FacebookAppSecret'));
this.facebook.supported(!!Settings.settingsGet('SupportedFacebookSocial'));
this.twitter.enabled = ko.observable(!!Settings.settingsGet('AllowTwitterSocial'));
this.twitter.consumerKey = ko.observable(Settings.settingsGet('TwitterConsumerKey'));
this.twitter.consumerSecret = ko.observable(Settings.settingsGet('TwitterConsumerSecret'));
this.dropbox.enabled(!!Settings.settingsGet('AllowDropboxSocial'));
this.dropbox.apiKey(Settings.settingsGet('DropboxApiKey'));
}
appendDropbox() {
if (!window.Dropbox && this.dropbox.enabled() && this.dropbox.apiKey()) {
if (!window.document.getElementById('dropboxjs')) {
const script = window.document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://www.dropbox.com/static/api/2/dropins.js';
$(script)
.attr('id', 'dropboxjs')
.attr('data-app-key', this.dropbox.apiKey());
window.document.body.appendChild(script);
}
}
}
}
export default new SocialStore();

View file

@ -1,47 +0,0 @@
@keyframes redirectingRotation {
to {
transform: rotate(1turn);
}
}
html, body {
padding: 0;
margin: 0;
overflow: hidden;
}
.social-icon-wrp {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
.social-icon {
position: absolute;
top: 50%;
left: 50%;
font-size: 140px;
margin: -60px 0 0 -60px;
color: #999;
}
.redirecting:after{
content: '';
position: absolute;
width: 240px;
height: 240px;
top: 50%;
left: 50%;
margin-top: -120px;
margin-left: -120px;
border: 8px solid transparent;
border-color: transparent;
border-top-color: #999;
animation: redirectingRotation 1s infinite ease-in-out;
border-radius: 50%;
z-index: 1;
}

View file

@ -49,7 +49,6 @@ import AccountStore from 'Stores/User/Account';
import FolderStore from 'Stores/User/Folder';
import PgpStore from 'Stores/User/Pgp';
import MessageStore from 'Stores/User/Message';
import SocialStore from 'Stores/Social';
import Remote from 'Remote/User/Ajax';
@ -329,21 +328,6 @@ class ComposePopupView extends AbstractViewNext {
this.showBcc.subscribe(this.resizerTrigger);
this.showReplyTo.subscribe(this.resizerTrigger);
this.dropboxEnabled = SocialStore.dropbox.enabled;
this.dropboxApiKey = SocialStore.dropbox.apiKey;
this.driveEnabled = ko.observable(
bXMLHttpRequestSupported &&
!!Settings.settingsGet('AllowGoogleSocial') &&
!!Settings.settingsGet('AllowGoogleSocialDrive') &&
!!Settings.settingsGet('GoogleClientID') &&
!!Settings.settingsGet('GoogleApiKey')
);
this.driveVisible = ko.observable(false);
this.driveCallback = _.bind(this.driveCallback, this);
this.onMessageUploadAttachments = _.bind(this.onMessageUploadAttachments, this);
this.bDisabeCloseOnEsc = true;
@ -530,28 +514,6 @@ class ComposePopupView extends AbstractViewNext {
}
}
@command((self) => self.dropboxEnabled())
dropboxCommand() {
if (window.Dropbox) {
window.Dropbox.choose({
success: (files) => {
if (files && files[0] && files[0].link) {
this.addDropboxAttachment(files[0]);
}
},
linkType: 'direct',
multiselect: false
});
}
return true;
}
@command((self) => self.driveEnabled())
driveCommand() {
this.driveOpenPopup();
return true;
}
autosaveFunction() {
if (
this.modalVisibility() &&
@ -1289,16 +1251,6 @@ class ComposePopupView extends AbstractViewNext {
Events.sub('window.resize.real', this.resizerTrigger);
Events.sub('window.resize.real', _.debounce(this.resizerTrigger, Magics.Time50ms));
SocialStore.appendDropbox();
if (this.driveEnabled()) {
$.getScript('https://apis.google.com/js/api.js', () => {
if (window.gapi) {
this.driveVisible(true);
}
});
}
window.setInterval(() => {
if (this.modalVisibility() && this.oEditor) {
this.oEditor.resize();
@ -1306,137 +1258,6 @@ class ComposePopupView extends AbstractViewNext {
}, Magics.Time5s);
}
driveCallback(accessToken, data) {
if (
data &&
window.XMLHttpRequest &&
window.google &&
data[window.google.picker.Response.ACTION] === window.google.picker.Action.PICKED &&
data[window.google.picker.Response.DOCUMENTS] &&
data[window.google.picker.Response.DOCUMENTS][0] &&
data[window.google.picker.Response.DOCUMENTS][0].id
) {
const request = new window.XMLHttpRequest();
request.open(
'GET',
'https://www.googleapis.com/drive/v2/files/' + data[window.google.picker.Response.DOCUMENTS][0].id
);
request.setRequestHeader('Authorization', 'Bearer ' + accessToken);
request.addEventListener('load', () => {
if (request && request.responseText) {
const response = window.JSON.parse(request.responseText),
fExport = (item, mimeType, ext) => {
if (item && item.exportLinks) {
if (item.exportLinks[mimeType]) {
response.downloadUrl = item.exportLinks[mimeType];
response.title = item.title + '.' + ext;
response.mimeType = mimeType;
} else if (item.exportLinks['application/pdf']) {
response.downloadUrl = item.exportLinks['application/pdf'];
response.title = item.title + '.pdf';
response.mimeType = 'application/pdf';
}
}
};
if (response && !response.downloadUrl && response.mimeType && response.exportLinks) {
switch (response.mimeType.toString().toLowerCase()) {
case 'application/vnd.google-apps.document':
fExport(response, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'docx');
break;
case 'application/vnd.google-apps.spreadsheet':
fExport(response, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'xlsx');
break;
case 'application/vnd.google-apps.drawing':
fExport(response, 'image/png', 'png');
break;
case 'application/vnd.google-apps.presentation':
fExport(response, 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'pptx');
break;
default:
fExport(response, 'application/pdf', 'pdf');
break;
}
}
if (response && response.downloadUrl) {
this.addDriveAttachment(response, accessToken);
}
}
});
request.send();
}
}
driveCreatePiker(authToken) {
if (window.gapi && authToken && authToken.access_token) {
window.gapi.load('picker', {
callback: () => {
if (window.google && window.google.picker) {
const drivePicker = new window.google.picker.PickerBuilder()
// .addView(window.google.picker.ViewId.FOLDERS)
.addView(window.google.picker.ViewId.DOCS)
.setAppId(Settings.settingsGet('GoogleClientID'))
.setOAuthToken(authToken.access_token)
.setCallback(_.bind(this.driveCallback, this, authToken.access_token))
.enableFeature(window.google.picker.Feature.NAV_HIDDEN)
// .setOrigin(window.location.protocol + '//' + window.location.host)
.build();
drivePicker.setVisible(true);
}
}
});
}
}
driveOpenPopup() {
if (window.gapi) {
window.gapi.load('auth', {
callback: () => {
const authToken = window.gapi.auth.getToken(),
fResult = (authResult) => {
if (authResult && !authResult.error) {
const token = window.gapi.auth.getToken();
if (token) {
this.driveCreatePiker(token);
}
return true;
}
return false;
};
if (!authToken) {
window.gapi.auth.authorize(
{
'client_id': Settings.settingsGet('GoogleClientID'),
'scope': 'https://www.googleapis.com/auth/drive.readonly',
'immediate': true
},
(authResult) => {
if (!fResult(authResult)) {
window.gapi.auth.authorize(
{
'client_id': Settings.settingsGet('GoogleClientID'),
'scope': 'https://www.googleapis.com/auth/drive.readonly',
'immediate': false
},
fResult
);
}
}
);
} else {
this.driveCreatePiker(authToken);
}
}
});
}
}
/**
* @param {string} id
* @returns {?Object}
@ -1643,83 +1464,6 @@ class ComposePopupView extends AbstractViewNext {
return attachment;
}
/**
* @param {Object} dropboxFile
* @returns {boolean}
*/
addDropboxAttachment(dropboxFile) {
const attachmentSizeLimit = pInt(Settings.settingsGet('AttachmentLimit')),
mSize = dropboxFile.bytes,
attachment = this.addAttachmentHelper(dropboxFile.link, dropboxFile.name, mSize);
if (0 < mSize && 0 < attachmentSizeLimit && attachmentSizeLimit < mSize) {
attachment.uploading(false).complete(true);
attachment.error(i18n('UPLOAD/ERROR_FILE_IS_TOO_BIG'));
return false;
}
Remote.composeUploadExternals(
(statusResult, data) => {
let result = false;
attachment.uploading(false).complete(true);
if (StorageResultType.Success === statusResult && data && data.Result) {
if (data.Result[attachment.id]) {
result = true;
attachment.tempName(data.Result[attachment.id]);
}
}
if (!result) {
attachment.error(getUploadErrorDescByCode(UploadErrorCode.FileNoUploaded));
}
},
[dropboxFile.link]
);
return true;
}
/**
* @param {Object} driveFile
* @param {string} accessToken
* @returns {boolean}
*/
addDriveAttachment(driveFile, accessToken) {
const attachmentSizeLimit = pInt(Settings.settingsGet('AttachmentLimit')),
size = driveFile.fileSize ? pInt(driveFile.fileSize) : 0,
attachment = this.addAttachmentHelper(driveFile.downloadUrl, driveFile.title, size);
if (0 < size && 0 < attachmentSizeLimit && attachmentSizeLimit < size) {
attachment.uploading(false).complete(true);
attachment.error(i18n('UPLOAD/ERROR_FILE_IS_TOO_BIG'));
return false;
}
Remote.composeUploadDrive(
(statusResult, data) => {
let result = false;
attachment.uploading(false).complete(true);
if (StorageResultType.Success === statusResult && data && data.Result) {
if (data.Result[attachment.id]) {
result = true;
attachment.tempName(data.Result[attachment.id][0]);
attachment.size(pInt(data.Result[attachment.id][1]));
}
}
if (!result) {
attachment.error(getUploadErrorDescByCode(UploadErrorCode.FileNoUploaded));
}
},
driveFile.downloadUrl,
accessToken
);
return true;
}
/**
* @param {MessageModel} message
* @param {string} type

View file

@ -14,7 +14,6 @@ import {
import { trim, inArray, pInt, convertLangName, triggerAutocompleteInputChange } from 'Common/Utils';
import { $win } from 'Common/Globals';
import { socialFacebook, socialGoogle, socialTwitter } from 'Common/Links';
import { getNotification, getNotificationFromResponse, reload as translatorReload } from 'Common/Translator';
import * as Plugins from 'Common/Plugins';
@ -141,19 +140,6 @@ class LoginUserView extends AbstractViewNext {
this.signMeVisibility = ko.computed(() => LoginSignMeType.Unused !== this.signMeType());
this.facebookLoginEnabled = ko.observable(false);
this.googleLoginEnabled = ko.observable(false);
this.googleGmailLoginEnabled = ko.observable(false);
this.twitterLoginEnabled = ko.observable(false);
this.socialLoginEnabled = ko.computed(() => {
const bF = this.facebookLoginEnabled(),
bG = this.googleLoginEnabled(),
bT = this.twitterLoginEnabled();
return bF || bG || bT;
});
if (Settings.settingsGet('AdditionalLoginError') && !this.submitError()) {
this.submitError(Settings.settingsGet('AdditionalLoginError'));
}
@ -163,30 +149,6 @@ class LoginUserView extends AbstractViewNext {
return `left=200,top=100,width=${wh},height=${wh},menubar=no,status=no,resizable=yes,scrollbars=yes`;
}
@command((self) => !self.submitRequest() && self.facebookLoginEnabled())
facebookCommand() {
window.open(socialFacebook(), 'Facebook', this.windowOpenFeatures(500));
return true;
}
@command((self) => !self.submitRequest() && self.googleLoginEnabled())
googleCommand() {
window.open(socialGoogle(), 'Google', this.windowOpenFeatures(550));
return true;
}
@command((self) => !self.submitRequest() && self.googleGmailLoginEnabled())
googleGmailCommand() {
window.open(socialGoogle(true), 'Google', this.windowOpenFeatures(550));
return true;
}
@command((self) => !self.submitRequest() && self.twitterLoginEnabled())
twitterCommand() {
window.open(socialTwitter(), 'Twitter', this.windowOpenFeatures(500));
return true;
}
@command((self) => !self.submitRequest())
submitCommand() {
triggerAutocompleteInputChange();
@ -328,25 +290,7 @@ class LoginUserView extends AbstractViewNext {
onBuild() {
const signMeLocal = Local.get(ClientSideKeyName.LastSignMe),
signMe = (Settings.settingsGet('SignMe') || 'unused').toLowerCase(),
jsHash = Settings.appSettingsGet('jsHash'),
fSocial = (iErrorCode) => {
iErrorCode = pInt(iErrorCode);
if (0 === iErrorCode) {
this.submitRequest(true);
getApp().loginAndLogoutReload(false);
} else {
this.submitError(getNotification(iErrorCode));
}
};
this.facebookLoginEnabled(!!Settings.settingsGet('AllowFacebookSocial'));
this.twitterLoginEnabled(!!Settings.settingsGet('AllowTwitterSocial'));
this.googleLoginEnabled(
!!Settings.settingsGet('AllowGoogleSocial') && !!Settings.settingsGet('AllowGoogleSocialAuth')
);
this.googleGmailLoginEnabled(
!!Settings.settingsGet('AllowGoogleSocial') && !!Settings.settingsGet('AllowGoogleSocialAuthGmail')
);
jsHash = Settings.appSettingsGet('jsHash');
switch (signMe) {
case LoginSignMeTypeAsString.DefaultOff:
@ -375,18 +319,6 @@ class LoginUserView extends AbstractViewNext {
this.email(AppStore.devEmail);
this.password(AppStore.devPassword);
if (this.googleLoginEnabled() || this.googleGmailLoginEnabled()) {
window['rl_' + jsHash + '_google_login_service'] = fSocial;
}
if (this.facebookLoginEnabled()) {
window['rl_' + jsHash + '_facebook_login_service'] = fSocial;
}
if (this.twitterLoginEnabled()) {
window['rl_' + jsHash + '_twitter_login_service'] = fSocial;
}
_.delay(() => {
LanguageStore.language.subscribe((value) => {
this.langRequest(true);

View file

@ -43,7 +43,6 @@ import { attachmentDownload } from 'Common/Links';
import { getUserPic, storeMessageFlagsToCache } from 'Common/Cache';
import SocialStore from 'Stores/Social';
import AppStore from 'Stores/User/App';
import SettingsStore from 'Stores/User/Settings';
import AccountStore from 'Stores/User/Account';
@ -144,46 +143,6 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
this.downloadAsZipLoading = ko.observable(false);
this.downloadAsZipError = ko.observable(false).extend({ falseTimeout: 7000 });
this.saveToOwnCloudAllowed = ko.computed(
() => -1 < inArray('owncloud', this.attachmentsActions()) && this.allowAttachmnetControls()
);
this.saveToOwnCloudLoading = ko.observable(false);
this.saveToOwnCloudSuccess = ko.observable(false).extend({ falseTimeout: 2000 });
this.saveToOwnCloudError = ko.observable(false).extend({ falseTimeout: 7000 });
this.saveToOwnCloudSuccess.subscribe((v) => {
if (v) {
this.saveToOwnCloudError(false);
}
});
this.saveToOwnCloudError.subscribe((v) => {
if (v) {
this.saveToOwnCloudSuccess(false);
}
});
this.saveToDropboxAllowed = ko.computed(
() => -1 < inArray('dropbox', this.attachmentsActions()) && this.allowAttachmnetControls()
);
this.saveToDropboxLoading = ko.observable(false);
this.saveToDropboxSuccess = ko.observable(false).extend({ falseTimeout: 2000 });
this.saveToDropboxError = ko.observable(false).extend({ falseTimeout: 7000 });
this.saveToDropboxSuccess.subscribe((v) => {
if (v) {
this.saveToDropboxError(false);
}
});
this.saveToDropboxError.subscribe((v) => {
if (v) {
this.saveToDropboxSuccess(false);
}
});
this.showAttachmnetControls.subscribe((v) => {
if (this.message()) {
_.each(this.message().attachments(), (item) => {
@ -243,9 +202,6 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
this.spamCommand = createCommandActionHelper(FolderType.Spam, true);
this.notSpamCommand = createCommandActionHelper(FolderType.NotSpam, true);
this.dropboxEnabled = SocialStore.dropbox.enabled;
this.dropboxApiKey = SocialStore.dropbox.apiKey;
// viewer
this.viewBodyTopValue = ko.observable(0);
@ -606,8 +562,6 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
Local.set(ClientSideKeyName.MessageHeaderFullInfo, value ? '1' : '0');
});
SocialStore.appendDropbox();
this.oHeaderDom = $('.messageItemHeader', dom);
this.oHeaderDom = this.oHeaderDom[0] ? this.oHeaderDom : null;
@ -956,77 +910,6 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
}
}
saveToOwnCloud() {
const hashes = this.getAttachmentsHashes();
if (0 < hashes.length) {
Promises.attachmentsActions('OwnCloud', hashes, this.saveToOwnCloudLoading)
.then((result) => {
if (result && result.Result) {
this.saveToOwnCloudSuccess(true);
} else {
this.saveToOwnCloudError(true);
}
})
.catch(() => {
this.saveToOwnCloudError(true);
});
} else {
this.highlightUnselectedAttachments(true);
}
}
saveToDropbox() {
const files = [],
hashes = this.getAttachmentsHashes();
if (0 < hashes.length) {
if (window.Dropbox) {
Promises.attachmentsActions('Dropbox', hashes, this.saveToDropboxLoading)
.then((result) => {
if (result && result.Result && result.Result.Url && result.Result.ShortLife && result.Result.Files) {
if (window.Dropbox && isArray(result.Result.Files)) {
_.each(result.Result.Files, (item) => {
files.push({
url: result.Result.Url + attachmentDownload(item.Hash, result.Result.ShortLife),
filename: item.FileName
});
});
window.Dropbox.save({
files: files,
progress: () => {
this.saveToDropboxLoading(true);
this.saveToDropboxError(false);
this.saveToDropboxSuccess(false);
},
cancel: () => {
this.saveToDropboxSuccess(false);
this.saveToDropboxError(false);
this.saveToDropboxLoading(false);
},
success: () => {
this.saveToDropboxSuccess(true);
this.saveToDropboxLoading(false);
},
error: () => {
this.saveToDropboxError(true);
this.saveToDropboxLoading(false);
}
});
} else {
this.saveToDropboxError(true);
}
}
})
.catch(() => {
this.saveToDropboxError(true);
});
}
} else {
this.highlightUnselectedAttachments(true);
}
}
/**
* @param {MessageModel} oMessage
* @returns {void}

View file

@ -21,7 +21,6 @@ window.progressJs.onbeforeend(() => {
}
});
require('../vendors/modernizr/modernizr-custom.js');
require('Common/Booter');
if (window.__runBoot) {

View file

@ -8,7 +8,6 @@ const { css, cssLint } = require('./tasks/css');
const { vendors } = require('./tasks/vendors');
const { watchCss } = require('./tasks/watch');
const { rainloop } = require('./tasks/rainloop');
const { owncloud } = require('./tasks/owncloud');
const clean = gulp.series(cleanStatic);
@ -27,5 +26,4 @@ exports.default = build;
exports.watchCss = watchCss;
exports.rainloop = gulp.series(build, rainloop);
exports.owncloud = gulp.series(build, owncloud);
exports.all = gulp.series(exports.rainloop, exports.owncloud);
exports.all = gulp.series(exports.rainloop);

View file

@ -4,7 +4,6 @@
"description": "Simple, modern & fast web-based email client",
"private": true,
"version": "1.14.0",
"ownCloudVersion": "5.3.0",
"homepage": "https://www.rainloop.net",
"author": {
"name": "RainLoop Team",

View file

@ -1,700 +0,0 @@
<?php
namespace TijsVerkoyen\CssToInlineStyles;
/**
* CSS to Inline Styles class
*
* @author Tijs Verkoyen <php-css-to-inline-styles@verkoyen.eu>
* @version 1.1.0
* @copyright Copyright (c), Tijs Verkoyen. All rights reserved.
* @license BSD License
*/
class CssToInlineStyles
{
/**
* The CSS to use
*
* @var string
*/
private $css;
/**
* The processed CSS rules
*
* @var array
*/
private $cssRules;
/**
* Should the generated HTML be cleaned
*
* @var bool
*/
private $cleanup = false;
/**
* The encoding to use.
*
* @var string
*/
private $encoding = 'UTF-8';
/**
* The HTML to process
*
* @var string
*/
private $html;
/**
* Use inline-styles block as CSS
*
* @var bool
*/
private $useInlineStylesBlock = false;
/*
* Strip original style tags
*
* @var bool
*/
private $stripOriginalStyleTags = false;
/**
* Creates an instance, you could set the HTML and CSS here, or load it
* later.
*
* @return void
* @param string[optional] $html The HTML to process.
* @param string[optional] $css The CSS to use.
*/
public function __construct($html = null, $css = null)
{
if($html !== null) $this->setHTML($html);
if($css !== null) $this->setCSS($css);
}
/**
* Convert a CSS-selector into an xPath-query
*
* @return string
* @param string $selector The CSS-selector.
*/
private function buildXPathQuery($selector)
{
// redefine
$selector = (string) $selector;
// the CSS selector
$cssSelector = array(
// E F, Matches any F element that is a descendant of an E element
'/(\w)\s+(\w)/',
// E > F, Matches any F element that is a child of an element E
'/(\w)\s*>\s*(\w)/',
// E:first-child, Matches element E when E is the first child of its parent
'/(\w):first-child/',
// E + F, Matches any F element immediately preceded by an element
'/(\w)\s*\+\s*(\w)/',
// E[foo], Matches any E element with the "foo" attribute set (whatever the value)
'/(\w)\[([\w\-]+)]/',
// E[foo="warning"], Matches any E element whose "foo" attribute value is exactly equal to "warning"
'/(\w)\[([\w\-]+)\=\"(.*)\"]/',
// div.warning, HTML only. The same as DIV[class~="warning"]
'/(\w+|\*)+\.([\w\-]+)+/',
// .warning, HTML only. The same as *[class~="warning"]
'/\.([\w\-]+)/',
// E#myid, Matches any E element with id-attribute equal to "myid"
'/(\w+)+\#([\w\-]+)/',
// #myid, Matches any element with id-attribute equal to "myid"
'/\#([\w\-]+)/'
);
// the xPath-equivalent
$xPathQuery = array(
// E F, Matches any F element that is a descendant of an E element
'\1//\2',
// E > F, Matches any F element that is a child of an element E
'\1/\2',
// E:first-child, Matches element E when E is the first child of its parent
'*[1]/self::\1',
// E + F, Matches any F element immediately preceded by an element
'\1/following-sibling::*[1]/self::\2',
// E[foo], Matches any E element with the "foo" attribute set (whatever the value)
'\1 [ @\2 ]',
// E[foo="warning"], Matches any E element whose "foo" attribute value is exactly equal to "warning"
'\1[ contains( concat( " ", @\2, " " ), concat( " ", "\3", " " ) ) ]',
// div.warning, HTML only. The same as DIV[class~="warning"]
'\1[ contains( concat( " ", @class, " " ), concat( " ", "\2", " " ) ) ]',
// .warning, HTML only. The same as *[class~="warning"]
'*[ contains( concat( " ", @class, " " ), concat( " ", "\1", " " ) ) ]',
// E#myid, Matches any E element with id-attribute equal to "myid"
'\1[ @id = "\2" ]',
// #myid, Matches any element with id-attribute equal to "myid"
'*[ @id = "\1" ]'
);
// return
$xPath = (string) '//' . preg_replace($cssSelector, $xPathQuery, $selector);
return str_replace('] *', ']//*', $xPath);
}
/**
* Calculate the specifity for the CSS-selector
*
* @return int
* @param string $selector The selector to calculate the specifity for.
*/
private function calculateCSSSpecifity($selector)
{
// cleanup selector
$selector = str_replace(array('>', '+'), array(' > ', ' + '), $selector);
// init var
$specifity = 0;
// split the selector into chunks based on spaces
$chunks = explode(' ', $selector);
// loop chunks
foreach ($chunks as $chunk) {
// an ID is important, so give it a high specifity
if(strstr($chunk, '#') !== false) $specifity += 100;
// classes are more important than a tag, but less important then an ID
elseif(strstr($chunk, '.')) $specifity += 10;
// anything else isn't that important
else $specifity += 1;
}
// return
return $specifity;
}
/**
* Cleanup the generated HTML
*
* @return string
* @param string $html The HTML to cleanup.
*/
private function cleanupHTML($html)
{
// remove classes
$html = preg_replace('/(\s)+class="(.*)"(\s)+/U', ' ', $html);
// remove IDs
$html = preg_replace('/(\s)+id="(.*)"(\s)+/U', ' ', $html);
// return
return $html;
}
/**
* Converts the loaded HTML into an HTML-string with inline styles based on the loaded CSS
*
* @return string
* @param bool[optional] $outputXHTML Should we output valid XHTML?
*/
public function convert($outputXHTML = false)
{
// redefine
$outputXHTML = (bool) $outputXHTML;
// validate
if($this->html == null) throw new Exception('No HTML provided.');
// should we use inline style-block
if ($this->useInlineStylesBlock) {
// init var
$matches = array();
// match the style blocks
preg_match_all('|<style(.*)>(.*)</style>|isU', $this->html, $matches);
// any style-blocks found?
if (!empty($matches[2])) {
// add
foreach($matches[2] as $match) $this->css .= trim($match) ."\n";
}
}
// process css
$this->processCSS();
// create new DOMDocument
$document = new \DOMDocument('1.0', $this->getEncoding());
// set error level
libxml_use_internal_errors(true);
// load HTML
// $document->loadHTML($this->html);
$document->loadHTML('<'.'?xml version="1.0" encoding="'.$this->getEncoding().'"?'.'><head><meta http-equiv="Content-Type" content="text/html; charset='.$this->getEncoding().'"></head>'.$this->html);
// create new XPath
$xPath = new \DOMXPath($document);
// any rules?
if (!empty($this->cssRules)) {
// loop rules
foreach ($this->cssRules as $rule) {
// init var
$query = $this->buildXPathQuery($rule['selector']);
// validate query
if($query === false) continue;
// search elements
$elements = $xPath->query($query);
// validate elements
if($elements === false) continue;
// loop found elements
foreach ($elements as $element) {
// no styles stored?
if ($element->attributes->getNamedItem(
'data-css-to-inline-styles-original-styles'
) == null) {
// init var
$originalStyle = '';
if ($element->attributes->getNamedItem('style') !== null) {
$originalStyle = $element->attributes->getNamedItem('style')->value;
}
// store original styles
$element->setAttribute(
'data-css-to-inline-styles-original-styles',
$originalStyle
);
// clear the styles
$element->setAttribute('style', '');
}
// init var
$properties = array();
// get current styles
$stylesAttribute = $element->attributes->getNamedItem('style');
// any styles defined before?
if ($stylesAttribute !== null) {
// get value for the styles attribute
$definedStyles = (string) $stylesAttribute->value;
// split into properties
$definedProperties = (array) explode(';', $definedStyles);
// loop properties
foreach ($definedProperties as $property) {
// validate property
if($property == '') continue;
// split into chunks
$chunks = (array) explode(':', trim($property), 2);
// validate
if(!isset($chunks[1])) continue;
// loop chunks
$properties[$chunks[0]] = trim($chunks[1]);
}
}
// add new properties into the list
foreach ($rule['properties'] as $key => $value) {
$properties[$key] = $value;
}
// build string
$propertyChunks = array();
// build chunks
foreach ($properties as $key => $values) {
foreach ((array) $values as $value) {
$propertyChunks[] = $key . ': ' . $value . ';';
}
}
// build properties string
$propertiesString = implode(' ', $propertyChunks);
// set attribute
if ($propertiesString != '') {
$element->setAttribute('style', $propertiesString);
}
}
}
// reapply original styles
$query = $this->buildXPathQuery(
'*[@data-css-to-inline-styles-original-styles]'
);
// validate query
if($query === false) return;
// search elements
$elements = $xPath->query($query);
// loop found elements
foreach ($elements as $element) {
// get the original styles
$originalStyle = $element->attributes->getNamedItem(
'data-css-to-inline-styles-original-styles'
)->value;
if ($originalStyle != '') {
$originalProperties = array();
$originalStyles = (array) explode(';', $originalStyle);
foreach ($originalStyles as $property) {
// validate property
if($property == '') continue;
// split into chunks
$chunks = (array) explode(':', trim($property), 2);
// validate
if(!isset($chunks[1])) continue;
// loop chunks
$originalProperties[$chunks[0]] = trim($chunks[1]);
}
// get current styles
$stylesAttribute = $element->attributes->getNamedItem('style');
$properties = array();
// any styles defined before?
if ($stylesAttribute !== null) {
// get value for the styles attribute
$definedStyles = (string) $stylesAttribute->value;
// split into properties
$definedProperties = (array) explode(';', $definedStyles);
// loop properties
foreach ($definedProperties as $property) {
// validate property
if($property == '') continue;
// split into chunks
$chunks = (array) explode(':', trim($property), 2);
// validate
if(!isset($chunks[1])) continue;
// loop chunks
$properties[$chunks[0]] = trim($chunks[1]);
}
}
// add new properties into the list
foreach ($originalProperties as $key => $value) {
$properties[$key] = $value;
}
// build string
$propertyChunks = array();
// build chunks
foreach ($properties as $key => $values) {
foreach ((array) $values as $value) {
$propertyChunks[] = $key . ': ' . $value . ';';
}
}
// build properties string
$propertiesString = implode(' ', $propertyChunks);
// set attribute
if($propertiesString != '') $element->setAttribute(
'style', $propertiesString
);
}
// remove placeholder
$element->removeAttribute(
'data-css-to-inline-styles-original-styles'
);
}
}
// should we output XHTML?
if ($outputXHTML) {
// set formating
$document->formatOutput = true;
// get the HTML as XML
$html = $document->saveXML(null, LIBXML_NOEMPTYTAG);
// get start of the XML-declaration
$startPosition = strpos($html, '<?xml');
// valid start position?
if ($startPosition !== false) {
// get end of the xml-declaration
$endPosition = strpos($html, '?>', $startPosition);
// remove the XML-header
$html = ltrim(substr($html, $endPosition + 1));
}
}
// just regular HTML 4.01 as it should be used in newsletters
else {
// get the HTML
$html = $document->saveHTML();
}
// cleanup the HTML if we need to
if($this->cleanup) $html = $this->cleanupHTML($html);
// strip original style tags if we need to
if ($this->stripOriginalStyleTags) {
$html = $this->stripOriginalStyleTags($html);
}
// return
return $html;
}
/**
* Get the encoding to use
*
* @return string
*/
private function getEncoding()
{
return $this->encoding;
}
/**
* Process the loaded CSS
*
* @return void
*/
private function processCSS()
{
// init vars
$css = (string) $this->css;
// remove newlines
$css = str_replace(array("\r", "\n"), '', $css);
// replace double quotes by single quotes
$css = str_replace('"', '\'', $css);
// remove comments
$css = preg_replace('|/\*.*?\*/|', '', $css);
// remove spaces
$css = preg_replace('/\s\s+/', ' ', $css);
// rules are splitted by }
$rules = (array) explode('}', $css);
// init var
$i = 1;
// loop rules
foreach ($rules as $rule) {
// split into chunks
$chunks = explode('{', $rule);
// invalid rule?
if(!isset($chunks[1])) continue;
// set the selectors
$selectors = trim($chunks[0]);
// get cssProperties
$cssProperties = trim($chunks[1]);
// split multiple selectors
$selectors = (array) explode(',', $selectors);
// loop selectors
foreach ($selectors as $selector) {
// cleanup
$selector = trim($selector);
// build an array for each selector
$ruleSet = array();
// store selector
$ruleSet['selector'] = $selector;
// process the properties
$ruleSet['properties'] = $this->processCSSProperties(
$cssProperties
);
// calculate specifity
$ruleSet['specifity'] = $this->calculateCSSSpecifity(
$selector
) + $i;
// add into global rules
$this->cssRules[] = $ruleSet;
}
// increment
$i++;
}
// sort based on specifity
if (!empty($this->cssRules)) {
usort($this->cssRules, array(__CLASS__, 'sortOnSpecifity'));
}
}
/**
* Process the CSS-properties
*
* @return array
* @param string $propertyString The CSS-properties.
*/
private function processCSSProperties($propertyString)
{
// split into chunks
$properties = (array) explode(';', $propertyString);
// init var
$pairs = array();
// loop properties
foreach ($properties as $property) {
// split into chunks
$chunks = (array) explode(':', $property, 2);
// validate
if(!isset($chunks[1])) continue;
// cleanup
$chunks[0] = trim($chunks[0]);
$chunks[1] = trim($chunks[1]);
// add to pairs array
if(!isset($pairs[$chunks[0]]) ||
!in_array($chunks[1], $pairs[$chunks[0]])) {
$pairs[$chunks[0]][] = $chunks[1];
}
}
// sort the pairs
ksort($pairs);
// return
return $pairs;
}
/**
* Should the IDs and classes be removed?
*
* @return void
* @param bool[optional] $on Should we enable cleanup?
*/
public function setCleanup($on = true)
{
$this->cleanup = (bool) $on;
}
/**
* Set CSS to use
*
* @return void
* @param string $css The CSS to use.
*/
public function setCSS($css)
{
$this->css = (string) $css;
}
/**
* Set the encoding to use with the DOMDocument
*
* @return void
* @param string $encoding The encoding to use.
*/
public function setEncoding($encoding)
{
$this->encoding = (string) $encoding;
}
/**
* Set HTML to process
*
* @return void
* @param string $html The HTML to process.
*/
public function setHTML($html)
{
$this->html = (string) $html;
}
/**
* Set use of inline styles block
* If this is enabled the class will use the style-block in the HTML.
*
* @return void
* @param bool[optional] $on Should we process inline styles?
*/
public function setUseInlineStylesBlock($on = true)
{
$this->useInlineStylesBlock = (bool) $on;
}
/**
* Set strip original style tags
* If this is enabled the class will remove all style tags in the HTML.
*
* @return void
* @param bool[optional] $onShould we process inline styles?
*/
public function setStripOriginalStyleTags($on = true)
{
$this->stripOriginalStyleTags = (bool) $on;
}
/**
* Strip style tags into the generated HTML
*
* @return string
* @param string $html The HTML to strip style tags.
*/
private function stripOriginalStyleTags($html)
{
return preg_replace('|<style(.*)>(.*)</style>|isU', '', $html);
}
/**
* Sort an array on the specifity element
*
* @return int
* @param array $e1 The first element.
* @param array $e2 The second element.
*/
private static function sortOnSpecifity($e1, $e2)
{
// validate
if(!isset($e1['specifity']) || !isset($e2['specifity'])) return 0;
// lower
if($e1['specifity'] < $e2['specifity']) return -1;
// higher
if($e1['specifity'] > $e2['specifity']) return 1;
// fallback
return 0;
}
}

View file

@ -1,20 +0,0 @@
The MIT License (MIT)
Copyright (c) 2013 RainLoop Team
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1 +0,0 @@
Plugin used for processing complex embedded styles in mail messages. In some cases, it can improve rendering HTML mails.

View file

@ -1,29 +0,0 @@
<?php
class ConvertHeadersStylesPlugin extends \RainLoop\Plugins\AbstractPlugin
{
public function Init()
{
$this->addHook('filter.result-message', 'FilterResultMessage');
}
/**
* @param \MailSo\Mail\Message &$oMessage
*/
public function FilterResultMessage(&$oMessage)
{
if ($oMessage)
{
$sHtml = $oMessage->Html();
if ($sHtml && 0 < strlen($sHtml))
{
include_once __DIR__.'/CssToInlineStyles.php';
$oCSSToInlineStyles = new \TijsVerkoyen\CssToInlineStyles\CssToInlineStyles($sHtml);
$oCSSToInlineStyles->setEncoding('utf-8');
$oCSSToInlineStyles->setUseInlineStylesBlock(true);
$oMessage->SetHtml($oCSSToInlineStyles->convert().'<!-- convert-headers-styles-plugin -->');
}
}
}
}

View file

@ -1,20 +0,0 @@
The MIT License (MIT)
Copyright (c) 2013 RainLoop Team
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,3 +0,0 @@
A CAPTCHA is a program that can generate and grade tests that humans can pass but current computer programs cannot.
For example, humans can read distorted text as the one shown below, but current computer programs can't.
More info at http://www.google.com/recaptcha

View file

@ -1 +0,0 @@
1.9

View file

@ -1,139 +0,0 @@
<?php
class RecaptchaPlugin extends \RainLoop\Plugins\AbstractPlugin
{
/**
* @return void
*/
public function Init()
{
$this->UseLangs(true);
$this->addJs('js/recaptcha.js');
$this->addHook('ajax.action-pre-call', 'AjaxActionPreCall');
$this->addHook('filter.ajax-response', 'FilterAjaxResponse');
$this->addTemplate('templates/PluginLoginReCaptchaGroup.html');
$this->addTemplateHook('Login', 'BottomControlGroup', 'PluginLoginReCaptchaGroup');
}
/**
* @return array
*/
public function configMapping()
{
return array(
\RainLoop\Plugins\Property::NewInstance('public_key')->SetLabel('Public Key')
->SetAllowedInJs(true)
->SetDefaultValue(''),
\RainLoop\Plugins\Property::NewInstance('private_key')->SetLabel('Private Key')
->SetDefaultValue(''),
\RainLoop\Plugins\Property::NewInstance('error_limit')->SetLabel('Limit')
->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION)
->SetDefaultValue(array(0, 1, 2, 3, 4, 5))
->SetDescription('')
);
}
/**
* @return string
*/
private function getCaptchaCacherKey()
{
return 'Captcha/Login/'.\RainLoop\Utils::GetConnectionToken();
}
/**
* @return int
*/
private function getLimit()
{
$iConfigLimit = $this->Config()->Get('plugin', 'error_limit', 0);
if (0 < $iConfigLimit)
{
$oCacher = $this->Manager()->Actions()->Cacher();
$sLimit = $oCacher && $oCacher->IsInited() ? $oCacher->Get($this->getCaptchaCacherKey()) : '0';
if (0 < strlen($sLimit) && is_numeric($sLimit))
{
$iConfigLimit -= (int) $sLimit;
}
}
return $iConfigLimit;
}
/**
* @return void
*/
public function FilterAppDataPluginSection($bAdmin, $bAuth, &$aData)
{
if (!$bAdmin && !$bAuth && is_array($aData))
{
$aData['show_captcha_on_login'] = 1 > $this->getLimit();
}
}
/**
* @param string $sAction
*/
public function AjaxActionPreCall($sAction)
{
if ('Login' === $sAction && 0 >= $this->getLimit())
{
require_once __DIR__.'/recaptchalib.php';
$oResp = recaptcha_check_answer(
$this->Config()->Get('plugin', 'private_key', ''),
isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '',
$this->Manager()->Actions()->GetActionParam('RecaptchaChallenge', ''),
$this->Manager()->Actions()->GetActionParam('RecaptchaResponse', '')
);
if (!$oResp || !isset($oResp->is_valid) || !$oResp->is_valid)
{
$this->Manager()->Actions()->Logger()->WriteDump($oResp);
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CaptchaError);
}
}
}
/**
* @param string $sAction
* @param array $aResponseItem
*/
public function FilterAjaxResponse($sAction, &$aResponseItem)
{
if ('Login' === $sAction && $aResponseItem && isset($aResponseItem['Result']))
{
$oCacher = $this->Manager()->Actions()->Cacher();
$iConfigLimit = (int) $this->Config()->Get('plugin', 'error_limit', 0);
$sKey = $this->getCaptchaCacherKey();
if (0 < $iConfigLimit && $oCacher && $oCacher->IsInited())
{
if (false === $aResponseItem['Result'])
{
$iLimit = 0;
$sLimut = $oCacher->Get($sKey);
if (0 < strlen($sLimut) && is_numeric($sLimut))
{
$iLimit = (int) $sLimut;
}
$oCacher->Set($sKey, ++$iLimit);
if ($iConfigLimit <= $iLimit)
{
$aResponseItem['Captcha'] = true;
}
}
else
{
$oCacher->Delete($sKey);
}
}
}
}
}

View file

@ -1,78 +0,0 @@
$(function () {
var
bStarted = false,
bShown = false
;
function ShowRecaptcha()
{
if (window.Recaptcha)
{
if (bShown)
{
window.Recaptcha.reload();
}
else
{
window.Recaptcha.create(window.rl.pluginSettingsGet('recaptcha', 'public_key'), 'recaptcha-place', {
'theme': 'custom',
'lang': window.rl.settingsGet('Language')
});
}
bShown = true;
}
}
function StartRecaptcha()
{
if (!window.Recaptcha)
{
$.getScript('//www.google.com/recaptcha/api/js/recaptcha_ajax.js', ShowRecaptcha);
}
else
{
ShowRecaptcha();
}
}
if (window.rl)
{
window.rl.addHook('view-model-on-show', function (sName, oViewModel) {
if (!bStarted && oViewModel &&
('View:RainLoop:Login' === sName || 'View/App/Login' === sName || 'LoginViewModel' === sName || 'LoginAppView' === sName) &&
window.rl.pluginSettingsGet('recaptcha', 'show_captcha_on_login'))
{
bStarted = true;
StartRecaptcha();
}
});
window.rl.addHook('ajax-default-request', function (sAction, oParameters) {
if ('Login' === sAction && oParameters && bShown && window.Recaptcha)
{
oParameters['RecaptchaChallenge'] = window.Recaptcha.get_challenge();
oParameters['RecaptchaResponse'] = window.Recaptcha.get_response();
}
});
window.rl.addHook('ajax-default-response', function (sAction, oData, sType) {
if ('Login' === sAction)
{
if (!oData || 'success' !== sType || !oData['Result'])
{
if (bShown && window.Recaptcha)
{
window.Recaptcha.reload();
}
else if (oData && oData['Captcha'])
{
StartRecaptcha();
}
}
}
});
}
});

View file

@ -1,2 +0,0 @@
[PLUGIN]
LABEL_ENTER_THE_WORDS_ABOVE = "Enter the words above"

View file

@ -1,2 +0,0 @@
[PLUGIN]
LABEL_ENTER_THE_WORDS_ABOVE = "Введите слова с изображения"

View file

@ -1,280 +0,0 @@
<?php
/*
* This is a PHP library that handles calling reCAPTCHA.
* - Documentation and latest version
* http://recaptcha.net/plugins/php/
* - Get a reCAPTCHA API Key
* https://www.google.com/recaptcha/admin/create
* - Discussion group
* http://groups.google.com/group/recaptcha
*
* Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net
* AUTHORS:
* Mike Crawford
* Ben Maurer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* The reCAPTCHA server URL's
*/
define("RECAPTCHA_API_SERVER", "http://www.google.com/recaptcha/api");
define("RECAPTCHA_API_SECURE_SERVER", "https://www.google.com/recaptcha/api");
define("RECAPTCHA_VERIFY_SERVER", "www.google.com");
/**
* Encodes the given data into a query string format
* @param $data - array of string elements to be encoded
* @return string - encoded request
*/
function _recaptcha_qsencode ($data) {
$req = "";
foreach ( $data as $key => $value )
$req .= $key . '=' . urlencode( stripslashes($value) ) . '&';
// Cut the last '&'
$req=substr($req,0,strlen($req)-1);
return $req;
}
/**
* Submits an HTTP POST to a reCAPTCHA server
* @param string $host
* @param string $path
* @param array $data
* @param int port
* @return array response
*/
function _recaptcha_http_post($host, $path, $data, $port = 80) {
$req = _recaptcha_qsencode ($data);
$http_request = "POST $path HTTP/1.0\r\n";
$http_request .= "Host: $host\r\n";
$http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
$http_request .= "Content-Length: " . strlen($req) . "\r\n";
$http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
$http_request .= "\r\n";
$http_request .= $req;
$response = '';
if( false == ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) {
die ('Could not open socket');
}
fwrite($fs, $http_request);
while ( !feof($fs) )
$response .= fgets($fs, 1160); // One TCP-IP packet
fclose($fs);
$response = explode("\r\n\r\n", $response, 2);
return $response;
}
/**
* Gets the challenge HTML (javascript and non-javascript version).
* This is called from the browser, and the resulting reCAPTCHA HTML widget
* is embedded within the HTML form it was called from.
* @param string $pubkey A public key for reCAPTCHA
* @param string $error The error given by reCAPTCHA (optional, default is null)
* @param boolean $use_ssl Should the request be made over ssl? (optional, default is false)
* @return string - The HTML to be embedded in the user's form.
*/
function recaptcha_get_html ($pubkey, $error = null, $use_ssl = false)
{
if ($pubkey == null || $pubkey == '') {
die ("To use reCAPTCHA you must get an API key from <a href='https://www.google.com/recaptcha/admin/create'>https://www.google.com/recaptcha/admin/create</a>");
}
if ($use_ssl) {
$server = RECAPTCHA_API_SECURE_SERVER;
} else {
$server = RECAPTCHA_API_SERVER;
}
$errorpart = "";
if ($error) {
$errorpart = "&amp;error=" . $error;
}
return '<script type="text/javascript" data-cfasync="false" src="'. $server . '/challenge?k=' . $pubkey . $errorpart . '"></script>
<noscript>
<iframe src="'. $server . '/noscript?k=' . $pubkey . $errorpart . '" height="300" width="500" frameborder="0"></iframe><br/>
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>
</noscript>';
}
/**
* A ReCaptchaResponse is returned from recaptcha_check_answer()
*/
class ReCaptchaResponse {
var $is_valid;
var $error;
}
/**
* Calls an HTTP POST function to verify if the user's guess was correct
* @param string $privkey
* @param string $remoteip
* @param string $challenge
* @param string $response
* @param array $extra_params an array of extra variables to post to the server
* @return ReCaptchaResponse
*/
function recaptcha_check_answer ($privkey, $remoteip, $challenge, $response, $extra_params = array())
{
if ($privkey == null || $privkey == '') {
$recaptcha_response = new ReCaptchaResponse();
$recaptcha_response->is_valid = false;
$recaptcha_response->error = 'To use reCAPTCHA you must get an API key from <a href=\'https://www.google.com/recaptcha/admin/create\'>https://www.google.com/recaptcha/admin/create</a>';
return $recaptcha_response;
}
if ($remoteip == null || $remoteip == '') {
$recaptcha_response = new ReCaptchaResponse();
$recaptcha_response->is_valid = false;
$recaptcha_response->error = 'For security reasons, you must pass the remote ip to reCAPTCHA';
return $recaptcha_response;
}
//discard spam submissions
if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) {
$recaptcha_response = new ReCaptchaResponse();
$recaptcha_response->is_valid = false;
$recaptcha_response->error = 'incorrect-captcha-sol';
return $recaptcha_response;
}
$response = _recaptcha_http_post (RECAPTCHA_VERIFY_SERVER, "/recaptcha/api/verify",
array (
'privatekey' => $privkey,
'remoteip' => $remoteip,
'challenge' => $challenge,
'response' => $response
) + $extra_params
);
$answers = explode ("\n", $response [1]);
$recaptcha_response = new ReCaptchaResponse();
if (trim ($answers [0]) == 'true') {
$recaptcha_response->is_valid = true;
}
else {
$recaptcha_response->is_valid = false;
$recaptcha_response->error = $answers [1];
}
return $recaptcha_response;
}
/**
* gets a URL where the user can sign up for reCAPTCHA. If your application
* has a configuration page where you enter a key, you should provide a link
* using this function.
* @param string $domain The domain where the page is hosted
* @param string $appname The name of your application
*/
function recaptcha_get_signup_url ($domain = null, $appname = null) {
return "https://www.google.com/recaptcha/admin/create?" . _recaptcha_qsencode (array ('domains' => $domain, 'app' => $appname));
}
function _recaptcha_aes_pad($val) {
$block_size = 16;
$numpad = $block_size - (strlen ($val) % $block_size);
return str_pad($val, strlen ($val) + $numpad, chr($numpad));
}
/* Mailhide related code */
function _recaptcha_aes_encrypt($val,$ky) {
if (! function_exists ("mcrypt_encrypt")) {
die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed.");
}
$mode=MCRYPT_MODE_CBC;
$enc=MCRYPT_RIJNDAEL_128;
$val=_recaptcha_aes_pad($val);
return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
}
function _recaptcha_mailhide_urlbase64 ($x) {
return strtr(base64_encode ($x), '+/', '-_');
}
/* gets the reCAPTCHA Mailhide url for a given email, public key and private key */
function recaptcha_mailhide_url($pubkey, $privkey, $email) {
if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) {
die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " .
"you can do so at <a href='http://www.google.com/recaptcha/mailhide/apikey'>http://www.google.com/recaptcha/mailhide/apikey</a>");
}
$ky = pack('H*', $privkey);
$cryptmail = _recaptcha_aes_encrypt ($email, $ky);
return "http://www.google.com/recaptcha/mailhide/d?k=" . $pubkey . "&c=" . _recaptcha_mailhide_urlbase64 ($cryptmail);
}
/**
* gets the parts of the email to expose to the user.
* eg, given johndoe@example,com return ["john", "example.com"].
* the email is then displayed as john...@example.com
*/
function _recaptcha_mailhide_email_parts ($email) {
$arr = preg_split("/@/", $email );
if (strlen ($arr[0]) <= 4) {
$arr[0] = substr ($arr[0], 0, 1);
} else if (strlen ($arr[0]) <= 6) {
$arr[0] = substr ($arr[0], 0, 3);
} else {
$arr[0] = substr ($arr[0], 0, 4);
}
return $arr;
}
/**
* Gets html to display an email address given a public an private key.
* to get a key, go to:
*
* http://www.google.com/recaptcha/mailhide/apikey
*/
function recaptcha_mailhide_html($pubkey, $privkey, $email) {
$emailparts = _recaptcha_mailhide_email_parts ($email);
$url = recaptcha_mailhide_url ($pubkey, $privkey, $email);
return htmlentities($emailparts[0]) . "<a href='" . htmlentities ($url) .
"' onclick=\"window.open('" . htmlentities ($url) . "', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;\" title=\"Reveal this e-mail address\">...</a>@" . htmlentities ($emailparts [1]);
}

View file

@ -1,18 +0,0 @@
<div class="recaptcha-control-group" id="recaptcha-place" style="display: none">
<div class="controls">
<div id="recaptcha_image" style="border-radius: 3px"></div>
</div>
<div class="controls">
<div class="input-append">
<input class="i18n input-block-level inputLoginForm inputCAPTCHA" type="text" autocomplete="off"
id="recaptcha_response_field" data-i18n-placeholder="PLUGIN/LABEL_ENTER_THE_WORDS_ABOVE"
data-i18n="[placeholder]PLUGIN/LABEL_ENTER_THE_WORDS_ABOVE" />
<span class="add-on">
<i class="icon-repeat" onclick="Recaptcha.reload()" style="cursor: pointer"></i>
</span>
</div>
</div>
</div>

View file

@ -172,7 +172,7 @@ class Api
}
}
protected static function Version() : string
public static function Version() : string
{
return APP_VERSION;
}

View file

@ -64,10 +64,6 @@ config.paths.css = {
'vendors/Progress.js/minified/progressjs.min.css',
'dev/Styles/_progressjs.css'
]
},
social: {
name: 'social.css',
src: ['vendors/fontastic/styles.css', 'dev/Styles/_social.css']
}
};

View file

@ -41,19 +41,6 @@ const cssMainBuild = () => {
.pipe(livereload());
};
const cssSocialBuild = () => {
const autoprefixer = require('gulp-autoprefixer'),
src = config.paths.css.social.src;
return gulp
.src(src)
.pipe(expect.real({ errorOnFailure: true }, src))
.pipe(concat(config.paths.css.social.name))
.pipe(autoprefixer())
.pipe(replace(/\.\.\/(img|images|fonts|svg)\//g, '$1/'))
.pipe(eol('\n', true))
.pipe(gulp.dest(config.paths.staticCSS));
};
const cssMainMin = () => {
const cleanCss = require('gulp-clean-css');
return gulp
@ -64,18 +51,8 @@ const cssMainMin = () => {
.pipe(gulp.dest(config.paths.staticCSS));
};
const cssSocialMin = () => {
const cleanCss = require('gulp-clean-css');
return gulp
.src(config.paths.staticCSS + config.paths.css.social.name)
.pipe(cleanCss())
.pipe(rename({ suffix: '.min' }))
.pipe(eol('\n', true))
.pipe(gulp.dest(config.paths.staticCSS));
};
const cssBuild = gulp.parallel(cssMainBuild, cssSocialBuild);
const cssMin = gulp.parallel(cssMainMin, cssSocialMin);
const cssBuild = gulp.parallel(cssMainBuild);
const cssMin = gulp.parallel(cssMainMin);
const cssLint = (done) => done();

View file

@ -1,96 +0,0 @@
/* RainLoop Webmail (c) RainLoop Team | Licensed under AGPL 3 */
/* eslint-disable consistent-return */
const gulp = require('gulp');
const fs = require('node-fs');
const pkg = require('../package.json');
const { config } = require('./config');
const { copy, zip, del } = require('./common');
const { rainloopBuild } = require('./rainloop');
const owncloudCopy = () => {
const versionFull = pkg.ownCloudVersion,
dist = config.releasesPath + '/owncloud/' + versionFull + '/src/';
fs.mkdirSync(dist, '0777', true);
fs.mkdirSync(dist + 'rainloop', '0777', true);
return gulp
.src('build/owncloud/rainloop-app/**/*', { base: 'build/owncloud/rainloop-app/' })
.pipe(gulp.dest(dist + 'rainloop'));
};
const owncloudCopyRainLoop = () => {
const versionFull = pkg.ownCloudVersion,
dist = config.releasesPath + '/owncloud/' + versionFull + '/src/rainloop/';
if (config.rainloopBuilded && config.destPath) {
return gulp.src(config.destPath + '/src/**/*', { base: config.destPath + '/src/' }).pipe(gulp.dest(dist + 'app/'));
}
return true;
};
const owncloudCopyRainLoopClean = (done) => {
if (config.cleanPath) {
return del(config.cleanPath);
}
done();
};
const owncloudSetup = (done) => {
const versionFull = pkg.ownCloudVersion,
dist = config.releasesPath + '/owncloud/' + versionFull + '/src/';
fs.writeFileSync(
dist + 'rainloop/appinfo/info.xml',
fs
.readFileSync(dist + 'rainloop/appinfo/info.xml', 'utf8')
.replace('<version>0.0</version>', '<version>' + versionFull + '</version>')
.replace(
'<licence></licence>',
'<licence>' + (config.community ? 'AGPLv3' : 'RainLoop Software License') + '</licence>'
)
);
fs.writeFileSync(dist + 'rainloop/appinfo/version', versionFull);
fs.writeFileSync(dist + 'rainloop/VERSION', versionFull);
config.destPath = config.releasesPath + '/owncloud/' + versionFull + '/';
config.cleanPath = dist;
config.zipSrcPath = dist;
config.zipFile = 'rainloop-owncloud-app-' + (config.community ? '' : 'standard-') + versionFull + '.zip';
config.zipFileShort = 'rainloop' + (config.community ? '' : '-standard') + '.zip';
done();
};
const owncloudZip = (done) => {
if (config.destPath && config.zipSrcPath && config.zipFile) {
return zip(config.zipSrcPath, config.destPath, config.zipFile);
}
done();
};
const owncloudClean = (done) => {
if (config.cleanPath) {
return del(config.cleanPath);
}
done();
};
const owncloudShortname = (done) => {
copy(config.destPath + config.zipFile, config.destPath + config.zipFileShort, done);
};
exports.owncloud = gulp.series(
owncloudCopy,
rainloopBuild,
owncloudCopyRainLoop,
owncloudCopyRainLoopClean,
owncloudSetup,
owncloudZip,
owncloudClean,
owncloudShortname
);

View file

@ -1,14 +0,0 @@
{
"minify": false,
"options": [
"setClasses"
],
"feature-detects": [
"test/css/animations",
"test/css/backgroundsize",
"test/css/boxshadow",
"test/css/rgba",
"test/css/textshadow",
"test/css/transitions"
]
}

View file

@ -1,905 +0,0 @@
/*!
* modernizr v3.3.1
* Build http://modernizr.com/download?-backgroundsize-boxshadow-cssanimations-csstransitions-rgba-textshadow-setclasses-dontmin
*
* Copyright (c)
* Faruk Ates
* Paul Irish
* Alex Sexton
* Ryan Seddon
* Patrick Kettner
* Stu Cox
* Richard Herrera
* MIT License
*/
/*
* Modernizr tests which native CSS3 and HTML5 features are available in the
* current UA and makes the results available to you in two ways: as properties on
* a global `Modernizr` object, and as classes on the `<html>` element. This
* information allows you to progressively enhance your pages with a granular level
* of control over the experience.
*/
;(function(window, document, undefined){
var classes = [];
var tests = [];
/**
*
* ModernizrProto is the constructor for Modernizr
*
* @class
* @access public
*/
var ModernizrProto = {
// The current version, dummy
_version: '3.3.1',
// Any settings that don't work as separate modules
// can go in here as configuration.
_config: {
'classPrefix': '',
'enableClasses': true,
'enableJSClass': true,
'usePrefixes': true
},
// Queue of tests
_q: [],
// Stub these for people who are listening
on: function(test, cb) {
// I don't really think people should do this, but we can
// safe guard it a bit.
// -- NOTE:: this gets WAY overridden in src/addTest for actual async tests.
// This is in case people listen to synchronous tests. I would leave it out,
// but the code to *disallow* sync tests in the real version of this
// function is actually larger than this.
var self = this;
setTimeout(function() {
cb(self[test]);
}, 0);
},
addTest: function(name, fn, options) {
tests.push({name: name, fn: fn, options: options});
},
addAsyncTest: function(fn) {
tests.push({name: null, fn: fn});
}
};
// Fake some of Object.create so we can force non test results to be non "own" properties.
var Modernizr = function() {};
Modernizr.prototype = ModernizrProto;
// Leak modernizr globally when you `require` it rather than force it here.
// Overwrite name so constructor name is nicer :D
Modernizr = new Modernizr();
/**
* is returns a boolean if the typeof an obj is exactly type.
*
* @access private
* @function is
* @param {*} obj - A thing we want to check the type of
* @param {string} type - A string to compare the typeof against
* @returns {boolean}
*/
function is(obj, type) {
return typeof obj === type;
}
;
/**
* Run through all tests and detect their support in the current UA.
*
* @access private
*/
function testRunner() {
var featureNames;
var feature;
var aliasIdx;
var result;
var nameIdx;
var featureName;
var featureNameSplit;
for (var featureIdx in tests) {
if (tests.hasOwnProperty(featureIdx)) {
featureNames = [];
feature = tests[featureIdx];
// run the test, throw the return value into the Modernizr,
// then based on that boolean, define an appropriate className
// and push it into an array of classes we'll join later.
//
// If there is no name, it's an 'async' test that is run,
// but not directly added to the object. That should
// be done with a post-run addTest call.
if (feature.name) {
featureNames.push(feature.name.toLowerCase());
if (feature.options && feature.options.aliases && feature.options.aliases.length) {
// Add all the aliases into the names list
for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) {
featureNames.push(feature.options.aliases[aliasIdx].toLowerCase());
}
}
}
// Run the test, or use the raw value if it's not a function
result = is(feature.fn, 'function') ? feature.fn() : feature.fn;
// Set each of the names on the Modernizr object
for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) {
featureName = featureNames[nameIdx];
// Support dot properties as sub tests. We don't do checking to make sure
// that the implied parent tests have been added. You must call them in
// order (either in the test, or make the parent test a dependency).
//
// Cap it to TWO to make the logic simple and because who needs that kind of subtesting
// hashtag famous last words
featureNameSplit = featureName.split('.');
if (featureNameSplit.length === 1) {
Modernizr[featureNameSplit[0]] = result;
} else {
// cast to a Boolean, if not one already
/* jshint -W053 */
if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
}
Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result;
}
classes.push((result ? '' : 'no-') + featureNameSplit.join('-'));
}
}
}
}
;
/**
* docElement is a convenience wrapper to grab the root element of the document
*
* @access private
* @returns {HTMLElement|SVGElement} The root element of the document
*/
var docElement = document.documentElement;
/**
* A convenience helper to check if the document we are running in is an SVG document
*
* @access private
* @returns {boolean}
*/
var isSVG = docElement.nodeName.toLowerCase() === 'svg';
/**
* setClasses takes an array of class names and adds them to the root element
*
* @access private
* @function setClasses
* @param {string[]} classes - Array of class names
*/
// Pass in an and array of class names, e.g.:
// ['no-webp', 'borderradius', ...]
function setClasses(classes) {
var className = docElement.className;
var classPrefix = Modernizr._config.classPrefix || '';
if (isSVG) {
className = className.baseVal;
}
// Change `no-js` to `js` (independently of the `enableClasses` option)
// Handle classPrefix on this too
if (Modernizr._config.enableJSClass) {
var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)');
className = className.replace(reJS, '$1' + classPrefix + 'js$2');
}
if (Modernizr._config.enableClasses) {
// Add the new classes
className += ' ' + classPrefix + classes.join(' ' + classPrefix);
isSVG ? docElement.className.baseVal = className : docElement.className = className;
}
}
;
/**
* createElement is a convenience wrapper around document.createElement. Since we
* use createElement all over the place, this allows for (slightly) smaller code
* as well as abstracting away issues with creating elements in contexts other than
* HTML documents (e.g. SVG documents).
*
* @access private
* @function createElement
* @returns {HTMLElement|SVGElement} An HTML or SVG element
*/
function createElement() {
if (typeof document.createElement !== 'function') {
// This is the case in IE7, where the type of createElement is "object".
// For this reason, we cannot call apply() as Object is not a Function.
return document.createElement(arguments[0]);
} else if (isSVG) {
return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]);
} else {
return document.createElement.apply(document, arguments);
}
}
;
/*!
{
"name": "CSS rgba",
"caniuse": "css3-colors",
"property": "rgba",
"tags": ["css"],
"notes": [{
"name": "CSSTricks Tutorial",
"href": "https://css-tricks.com/rgba-browser-support/"
}]
}
!*/
Modernizr.addTest('rgba', function() {
var style = createElement('a').style;
style.cssText = 'background-color:rgba(150,255,150,.5)';
return ('' + style.backgroundColor).indexOf('rgba') > -1;
});
/**
* contains checks to see if a string contains another string
*
* @access private
* @function contains
* @param {string} str - The string we want to check for substrings
* @param {string} substr - The substring we want to search the first string for
* @returns {boolean}
*/
function contains(str, substr) {
return !!~('' + str).indexOf(substr);
}
;
/**
* cssToDOM takes a kebab-case string and converts it to camelCase
* e.g. box-sizing -> boxSizing
*
* @access private
* @function cssToDOM
* @param {string} name - String name of kebab-case prop we want to convert
* @returns {string} The camelCase version of the supplied name
*/
function cssToDOM(name) {
return name.replace(/([a-z])-([a-z])/g, function(str, m1, m2) {
return m1 + m2.toUpperCase();
}).replace(/^-/, '');
}
;
/**
* If the browsers follow the spec, then they would expose vendor-specific style as:
* elem.style.WebkitBorderRadius
* instead of something like the following, which would be technically incorrect:
* elem.style.webkitBorderRadius
* Webkit ghosts their properties in lowercase but Opera & Moz do not.
* Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
* erik.eae.net/archives/2008/03/10/21.48.10/
* More here: github.com/Modernizr/Modernizr/issues/issue/21
*
* @access private
* @returns {string} The string representing the vendor-specific style properties
*/
var omPrefixes = 'Moz O ms Webkit';
var cssomPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.split(' ') : []);
ModernizrProto._cssomPrefixes = cssomPrefixes;
/**
* List of JavaScript DOM values used for tests
*
* @memberof Modernizr
* @name Modernizr._domPrefixes
* @optionName Modernizr._domPrefixes
* @optionProp domPrefixes
* @access public
* @example
*
* Modernizr._domPrefixes is exactly the same as [_prefixes](#modernizr-_prefixes), but rather
* than kebab-case properties, all properties are their Capitalized variant
*
* ```js
* Modernizr._domPrefixes === [ "Moz", "O", "ms", "Webkit" ];
* ```
*/
var domPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.toLowerCase().split(' ') : []);
ModernizrProto._domPrefixes = domPrefixes;
/**
* fnBind is a super small [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) polyfill.
*
* @access private
* @function fnBind
* @param {function} fn - a function you want to change `this` reference to
* @param {object} that - the `this` you want to call the function with
* @returns {function} The wrapped version of the supplied function
*/
function fnBind(fn, that) {
return function() {
return fn.apply(that, arguments);
};
}
;
/**
* testDOMProps is a generic DOM property test; if a browser supports
* a certain property, it won't return undefined for it.
*
* @access private
* @function testDOMProps
* @param {array.<string>} props - An array of properties to test for
* @param {object} obj - An object or Element you want to use to test the parameters again
* @param {boolean|object} elem - An Element to bind the property lookup again. Use `false` to prevent the check
*/
function testDOMProps(props, obj, elem) {
var item;
for (var i in props) {
if (props[i] in obj) {
// return the property name as a string
if (elem === false) {
return props[i];
}
item = obj[props[i]];
// let's bind a function
if (is(item, 'function')) {
// bind to obj unless overriden
return fnBind(item, elem || obj);
}
// return the unbound function or obj or value
return item;
}
}
return false;
}
;
/**
* Create our "modernizr" element that we do most feature tests on.
*
* @access private
*/
var modElem = {
elem: createElement('modernizr')
};
// Clean up this element
Modernizr._q.push(function() {
delete modElem.elem;
});
var mStyle = {
style: modElem.elem.style
};
// kill ref for gc, must happen before mod.elem is removed, so we unshift on to
// the front of the queue.
Modernizr._q.unshift(function() {
delete mStyle.style;
});
/**
* domToCSS takes a camelCase string and converts it to kebab-case
* e.g. boxSizing -> box-sizing
*
* @access private
* @function domToCSS
* @param {string} name - String name of camelCase prop we want to convert
* @returns {string} The kebab-case version of the supplied name
*/
function domToCSS(name) {
return name.replace(/([A-Z])/g, function(str, m1) {
return '-' + m1.toLowerCase();
}).replace(/^ms-/, '-ms-');
}
;
/**
* getBody returns the body of a document, or an element that can stand in for
* the body if a real body does not exist
*
* @access private
* @function getBody
* @returns {HTMLElement|SVGElement} Returns the real body of a document, or an
* artificially created element that stands in for the body
*/
function getBody() {
// After page load injecting a fake body doesn't work so check if body exists
var body = document.body;
if (!body) {
// Can't use the real body create a fake one.
body = createElement(isSVG ? 'svg' : 'body');
body.fake = true;
}
return body;
}
;
/**
* injectElementWithStyles injects an element with style element and some CSS rules
*
* @access private
* @function injectElementWithStyles
* @param {string} rule - String representing a css rule
* @param {function} callback - A function that is used to test the injected element
* @param {number} [nodes] - An integer representing the number of additional nodes you want injected
* @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
* @returns {boolean}
*/
function injectElementWithStyles(rule, callback, nodes, testnames) {
var mod = 'modernizr';
var style;
var ret;
var node;
var docOverflow;
var div = createElement('div');
var body = getBody();
if (parseInt(nodes, 10)) {
// In order not to give false positives we create a node for each test
// This also allows the method to scale for unspecified uses
while (nodes--) {
node = createElement('div');
node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
div.appendChild(node);
}
}
style = createElement('style');
style.type = 'text/css';
style.id = 's' + mod;
// IE6 will false positive on some tests due to the style element inside the test div somehow interfering offsetHeight, so insert it into body or fakebody.
// Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
(!body.fake ? div : body).appendChild(style);
body.appendChild(div);
if (style.styleSheet) {
style.styleSheet.cssText = rule;
} else {
style.appendChild(document.createTextNode(rule));
}
div.id = mod;
if (body.fake) {
//avoid crashing IE8, if background image is used
body.style.background = '';
//Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
body.style.overflow = 'hidden';
docOverflow = docElement.style.overflow;
docElement.style.overflow = 'hidden';
docElement.appendChild(body);
}
ret = callback(div, rule);
// If this is done after page load we don't want to remove the body so check if body exists
if (body.fake) {
body.parentNode.removeChild(body);
docElement.style.overflow = docOverflow;
// Trigger layout so kinetic scrolling isn't disabled in iOS6+
docElement.offsetHeight;
} else {
div.parentNode.removeChild(div);
}
return !!ret;
}
;
/**
* nativeTestProps allows for us to use native feature detection functionality if available.
* some prefixed form, or false, in the case of an unsupported rule
*
* @access private
* @function nativeTestProps
* @param {array} props - An array of property names
* @param {string} value - A string representing the value we want to check via @supports
* @returns {boolean|undefined} A boolean when @supports exists, undefined otherwise
*/
// Accepts a list of property names and a single value
// Returns `undefined` if native detection not available
function nativeTestProps(props, value) {
var i = props.length;
// Start with the JS API: http://www.w3.org/TR/css3-conditional/#the-css-interface
if ('CSS' in window && 'supports' in window.CSS) {
// Try every prefixed variant of the property
while (i--) {
if (window.CSS.supports(domToCSS(props[i]), value)) {
return true;
}
}
return false;
}
// Otherwise fall back to at-rule (for Opera 12.x)
else if ('CSSSupportsRule' in window) {
// Build a condition string for every prefixed variant
var conditionText = [];
while (i--) {
conditionText.push('(' + domToCSS(props[i]) + ':' + value + ')');
}
conditionText = conditionText.join(' or ');
return injectElementWithStyles('@supports (' + conditionText + ') { #modernizr { position: absolute; } }', function(node) {
return getComputedStyle(node, null).position == 'absolute';
});
}
return undefined;
}
;
// testProps is a generic CSS / DOM property test.
// In testing support for a given CSS property, it's legit to test:
// `elem.style[styleName] !== undefined`
// If the property is supported it will return an empty string,
// if unsupported it will return undefined.
// We'll take advantage of this quick test and skip setting a style
// on our modernizr element, but instead just testing undefined vs
// empty string.
// Property names can be provided in either camelCase or kebab-case.
function testProps(props, prefixed, value, skipValueTest) {
skipValueTest = is(skipValueTest, 'undefined') ? false : skipValueTest;
// Try native detect first
if (!is(value, 'undefined')) {
var result = nativeTestProps(props, value);
if (!is(result, 'undefined')) {
return result;
}
}
// Otherwise do it properly
var afterInit, i, propsLength, prop, before;
// If we don't have a style element, that means we're running async or after
// the core tests, so we'll need to create our own elements to use
// inside of an SVG element, in certain browsers, the `style` element is only
// defined for valid tags. Therefore, if `modernizr` does not have one, we
// fall back to a less used element and hope for the best.
var elems = ['modernizr', 'tspan'];
while (!mStyle.style) {
afterInit = true;
mStyle.modElem = createElement(elems.shift());
mStyle.style = mStyle.modElem.style;
}
// Delete the objects if we created them.
function cleanElems() {
if (afterInit) {
delete mStyle.style;
delete mStyle.modElem;
}
}
propsLength = props.length;
for (i = 0; i < propsLength; i++) {
prop = props[i];
before = mStyle.style[prop];
if (contains(prop, '-')) {
prop = cssToDOM(prop);
}
if (mStyle.style[prop] !== undefined) {
// If value to test has been passed in, do a set-and-check test.
// 0 (integer) is a valid property value, so check that `value` isn't
// undefined, rather than just checking it's truthy.
if (!skipValueTest && !is(value, 'undefined')) {
// Needs a try catch block because of old IE. This is slow, but will
// be avoided in most cases because `skipValueTest` will be used.
try {
mStyle.style[prop] = value;
} catch (e) {}
// If the property value has changed, we assume the value used is
// supported. If `value` is empty string, it'll fail here (because
// it hasn't changed), which matches how browsers have implemented
// CSS.supports()
if (mStyle.style[prop] != before) {
cleanElems();
return prefixed == 'pfx' ? prop : true;
}
}
// Otherwise just return true, or the property name if this is a
// `prefixed()` call
else {
cleanElems();
return prefixed == 'pfx' ? prop : true;
}
}
}
cleanElems();
return false;
}
;
/**
* testProp() investigates whether a given style property is recognized
* Property names can be provided in either camelCase or kebab-case.
*
* @memberof Modernizr
* @name Modernizr.testProp
* @access public
* @optionName Modernizr.testProp()
* @optionProp testProp
* @function testProp
* @param {string} prop - Name of the CSS property to check
* @param {string} [value] - Name of the CSS value to check
* @param {boolean} [useValue] - Whether or not to check the value if @supports isn't supported
* @returns {boolean}
* @example
*
* Just like [testAllProps](#modernizr-testallprops), only it does not check any vendor prefixed
* version of the string.
*
* Note that the property name must be provided in camelCase (e.g. boxSizing not box-sizing)
*
* ```js
* Modernizr.testProp('pointerEvents') // true
* ```
*
* You can also provide a value as an optional second argument to check if a
* specific value is supported
*
* ```js
* Modernizr.testProp('pointerEvents', 'none') // true
* Modernizr.testProp('pointerEvents', 'penguin') // false
* ```
*/
var testProp = ModernizrProto.testProp = function(prop, value, useValue) {
return testProps([prop], undefined, value, useValue);
};
/*!
{
"name": "CSS textshadow",
"property": "textshadow",
"caniuse": "css-textshadow",
"tags": ["css"],
"knownBugs": ["FF3.0 will false positive on this test"]
}
!*/
Modernizr.addTest('textshadow', testProp('textShadow', '1px 1px'));
/**
* testPropsAll tests a list of DOM properties we want to check against.
* We specify literally ALL possible (known and/or likely) properties on
* the element including the non-vendor prefixed one, for forward-
* compatibility.
*
* @access private
* @function testPropsAll
* @param {string} prop - A string of the property to test for
* @param {string|object} [prefixed] - An object to check the prefixed properties on. Use a string to skip
* @param {HTMLElement|SVGElement} [elem] - An element used to test the property and value against
* @param {string} [value] - A string of a css value
* @param {boolean} [skipValueTest] - An boolean representing if you want to test if value sticks when set
*/
function testPropsAll(prop, prefixed, elem, value, skipValueTest) {
var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
// did they call .prefixed('boxSizing') or are we just testing a prop?
if (is(prefixed, 'string') || is(prefixed, 'undefined')) {
return testProps(props, prefixed, value, skipValueTest);
// otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
} else {
props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
return testDOMProps(props, prefixed, elem);
}
}
// Modernizr.testAllProps() investigates whether a given style property,
// or any of its vendor-prefixed variants, is recognized
//
// Note that the property names must be provided in the camelCase variant.
// Modernizr.testAllProps('boxSizing')
ModernizrProto.testAllProps = testPropsAll;
/**
* testAllProps determines whether a given CSS property is supported in the browser
*
* @memberof Modernizr
* @name Modernizr.testAllProps
* @optionName Modernizr.testAllProps()
* @optionProp testAllProps
* @access public
* @function testAllProps
* @param {string} prop - String naming the property to test (either camelCase or kebab-case)
* @param {string} [value] - String of the value to test
* @param {boolean} [skipValueTest=false] - Whether to skip testing that the value is supported when using non-native detection
* @example
*
* testAllProps determines whether a given CSS property, in some prefixed form,
* is supported by the browser.
*
* ```js
* testAllProps('boxSizing') // true
* ```
*
* It can optionally be given a CSS value in string form to test if a property
* value is valid
*
* ```js
* testAllProps('display', 'block') // true
* testAllProps('display', 'penguin') // false
* ```
*
* A boolean can be passed as a third parameter to skip the value check when
* native detection (@supports) isn't available.
*
* ```js
* testAllProps('shapeOutside', 'content-box', true);
* ```
*/
function testAllProps(prop, value, skipValueTest) {
return testPropsAll(prop, undefined, undefined, value, skipValueTest);
}
ModernizrProto.testAllProps = testAllProps;
/*!
{
"name": "CSS Animations",
"property": "cssanimations",
"caniuse": "css-animation",
"polyfills": ["transformie", "csssandpaper"],
"tags": ["css"],
"warnings": ["Android < 4 will pass this test, but can only animate a single property at a time"],
"notes": [{
"name" : "Article: 'Dispelling the Android CSS animation myths'",
"href": "https://goo.gl/OGw5Gm"
}]
}
!*/
/* DOC
Detects whether or not elements can be animated using CSS
*/
Modernizr.addTest('cssanimations', testAllProps('animationName', 'a', true));
/*!
{
"name": "Background Size",
"property": "backgroundsize",
"tags": ["css"],
"knownBugs": ["This will false positive in Opera Mini - https://github.com/Modernizr/Modernizr/issues/396"],
"notes": [{
"name": "Related Issue",
"href": "https://github.com/Modernizr/Modernizr/issues/396"
}]
}
!*/
Modernizr.addTest('backgroundsize', testAllProps('backgroundSize', '100%', true));
/*!
{
"name": "CSS Transitions",
"property": "csstransitions",
"caniuse": "css-transitions",
"tags": ["css"]
}
!*/
Modernizr.addTest('csstransitions', testAllProps('transition', 'all', true));
/*!
{
"name": "Box Shadow",
"property": "boxshadow",
"caniuse": "css-boxshadow",
"tags": ["css"],
"knownBugs": [
"WebOS false positives on this test.",
"The Kindle Silk browser false positives"
]
}
!*/
Modernizr.addTest('boxshadow', testAllProps('boxShadow', '1px 1px', true));
// Run each test
testRunner();
// Remove the "no-js" class if it exists
setClasses(classes);
delete ModernizrProto.addTest;
delete ModernizrProto.addAsyncTest;
// Run the things that are supposed to run after the tests
for (var i = 0; i < Modernizr._q.length; i++) {
Modernizr._q[i]();
}
// Leak Modernizr namespace
window.Modernizr = Modernizr;
;
})(window, document);