mirror of
https://github.com/RaspbianFrance/raspisms.git
synced 2025-10-25 19:30:02 +02:00
Add multiple new functions :
- A new adapter for Odyssey Messaging - Feature to associate a tag to sms campaign - Support for phone groups - Support of phone status - Support for phone priority - Support for phone limits - Settings to enable phone priority and phone limits
This commit is contained in:
commit
eba0b83b87
73 changed files with 7138 additions and 1005 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
v3.5.5
|
||||
v3.6.0
|
||||
|
|
|
|||
|
|
@ -79,6 +79,11 @@ interface AdapterInterface
|
|||
*/
|
||||
public static function meta_support_read(): bool;
|
||||
|
||||
/**
|
||||
* Does the implemented service support updating phone status.
|
||||
*/
|
||||
public static function meta_support_phone_status(): bool;
|
||||
|
||||
/**
|
||||
* Does the implemented service support reception callback.
|
||||
*/
|
||||
|
|
@ -152,6 +157,15 @@ interface AdapterInterface
|
|||
*/
|
||||
public function test(): bool;
|
||||
|
||||
|
||||
/**
|
||||
* Method called to verify phone status
|
||||
*
|
||||
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
|
||||
*/
|
||||
public function check_phone_status(): string;
|
||||
|
||||
|
||||
/**
|
||||
* Method called on reception of a status update notification for a SMS.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -111,6 +111,14 @@ namespace adapters;
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support updating phone status.
|
||||
*/
|
||||
public static function meta_support_phone_status(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support flash smss.
|
||||
*/
|
||||
|
|
@ -226,6 +234,16 @@ namespace adapters;
|
|||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called to verify phone status
|
||||
*
|
||||
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
|
||||
*/
|
||||
public function check_phone_status(): string
|
||||
{
|
||||
return \models\Phone::STATUS_AVAILABLE;
|
||||
}
|
||||
|
||||
public static function status_change_callback()
|
||||
{
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -121,6 +121,14 @@ namespace adapters;
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support updating phone status.
|
||||
*/
|
||||
public static function meta_support_phone_status(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support flash smss.
|
||||
*/
|
||||
|
|
@ -301,6 +309,16 @@ namespace adapters;
|
|||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called to verify phone status
|
||||
*
|
||||
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
|
||||
*/
|
||||
public function check_phone_status(): string
|
||||
{
|
||||
return \models\Phone::STATUS_AVAILABLE;
|
||||
}
|
||||
|
||||
public function test(): bool
|
||||
{
|
||||
//Always return true as we cannot test because we would be needing a root account
|
||||
|
|
|
|||
|
|
@ -209,6 +209,14 @@ class KannelAdapter implements AdapterInterface
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support updating phone status.
|
||||
*/
|
||||
public static function meta_support_phone_status(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support flash smss.
|
||||
*/
|
||||
|
|
@ -354,6 +362,16 @@ class KannelAdapter implements AdapterInterface
|
|||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called to verify phone status
|
||||
*
|
||||
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
|
||||
*/
|
||||
public function check_phone_status(): string
|
||||
{
|
||||
return \models\Phone::STATUS_AVAILABLE;
|
||||
}
|
||||
|
||||
public function test(): bool
|
||||
{
|
||||
try
|
||||
|
|
|
|||
|
|
@ -174,6 +174,14 @@ class OctopushShortcodeAdapter implements AdapterInterface
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support updating phone status.
|
||||
*/
|
||||
public static function meta_support_phone_status(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support flash smss.
|
||||
*/
|
||||
|
|
@ -325,6 +333,16 @@ class OctopushShortcodeAdapter implements AdapterInterface
|
|||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called to verify phone status
|
||||
*
|
||||
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
|
||||
*/
|
||||
public function check_phone_status(): string
|
||||
{
|
||||
return \models\Phone::STATUS_AVAILABLE;
|
||||
}
|
||||
|
||||
public function test(): bool
|
||||
{
|
||||
try
|
||||
|
|
|
|||
|
|
@ -173,6 +173,14 @@ class OctopushVirtualNumberAdapter implements AdapterInterface
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support updating phone status.
|
||||
*/
|
||||
public static function meta_support_phone_status(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support flash smss.
|
||||
*/
|
||||
|
|
@ -317,6 +325,16 @@ class OctopushVirtualNumberAdapter implements AdapterInterface
|
|||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called to verify phone status
|
||||
*
|
||||
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
|
||||
*/
|
||||
public function check_phone_status(): string
|
||||
{
|
||||
return \models\Phone::STATUS_AVAILABLE;
|
||||
}
|
||||
|
||||
public function test(): bool
|
||||
{
|
||||
try
|
||||
|
|
|
|||
511
adapters/OdysseyMessagingAdapter.php
Normal file
511
adapters/OdysseyMessagingAdapter.php
Normal file
|
|
@ -0,0 +1,511 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of RaspiSMS.
|
||||
*
|
||||
* (c) Pierre-Lin Bonnemaison <plebwebsas@gmail.com>
|
||||
*
|
||||
* This source file is subject to the GPL-3.0 license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace adapters;
|
||||
|
||||
use DateTime;
|
||||
|
||||
/**
|
||||
* Odyssey Messaging SMS service
|
||||
*/
|
||||
class OdysseyMessagingAdapter implements AdapterInterface
|
||||
{
|
||||
const EVENT_TYPES = [
|
||||
'OPT_OUT' => 1,
|
||||
'SYSTEM_ERROR' => 2,
|
||||
'END_OF_ITEM' => 3,
|
||||
'END_OF_JOB' => 4,
|
||||
'JOB_STATUS_CHANGED' => 5,
|
||||
'REAL_TIME_STATUS' => 6,
|
||||
'RETRIEVE_FILE' => 7,
|
||||
'INBOUND_SMS' => 8,
|
||||
'ITEM_STATUS_CHANGED' => 9,
|
||||
'DATA_COLLECTION_FILLED' => 10,
|
||||
];
|
||||
|
||||
/**
|
||||
* Data used to configure interaction with the implemented service. (e.g : Api credentials, ports numbers, etc.).
|
||||
*/
|
||||
private $data;
|
||||
|
||||
/**
|
||||
* Odyssey login.
|
||||
*/
|
||||
private $login;
|
||||
|
||||
/**
|
||||
* Odyssey password.
|
||||
*/
|
||||
private $password;
|
||||
|
||||
/**
|
||||
* Sender name to use instead of shortcode.
|
||||
*/
|
||||
private $sender;
|
||||
|
||||
/**
|
||||
* Odyssey api baseurl.
|
||||
*/
|
||||
private $api_url = 'https://api.odyssey-services.fr/api/v1';
|
||||
|
||||
/**
|
||||
* Adapter constructor, called when instanciated by RaspiSMS.
|
||||
*
|
||||
* @param json string $data : JSON string of the data to configure interaction with the implemented service
|
||||
*/
|
||||
public function __construct(string $data)
|
||||
{
|
||||
$this->data = json_decode($data, true);
|
||||
|
||||
$this->login = $this->data['login'];
|
||||
$this->password = $this->data['password'];
|
||||
|
||||
$this->sender = $this->data['sender'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Classname of the adapter.
|
||||
*/
|
||||
public static function meta_classname(): string
|
||||
{
|
||||
return __CLASS__;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uniq name of the adapter
|
||||
* It should be the classname of the adapter un snakecase.
|
||||
*/
|
||||
public static function meta_uid(): string
|
||||
{
|
||||
return 'odyssey_messaging_adapter';
|
||||
}
|
||||
|
||||
/**
|
||||
* Should this adapter be hidden in user interface for phone creation and
|
||||
* available to creation through API only.
|
||||
*/
|
||||
public static function meta_hidden(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should this adapter data be hidden after creation
|
||||
* this help to prevent API credentials to other service leak if an attacker gain access to RaspiSMS through user credentials.
|
||||
*/
|
||||
public static function meta_hide_data(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the adapter.
|
||||
* It should probably be the name of the service it adapt (e.g : Gammu SMSD, OVH SMS, SIM800L, etc.).
|
||||
*/
|
||||
public static function meta_name(): string
|
||||
{
|
||||
return 'Odyssey Messaging';
|
||||
}
|
||||
|
||||
/**
|
||||
* Description of the adapter.
|
||||
* A short description of the service the adapter implements.
|
||||
*/
|
||||
public static function meta_description(): string
|
||||
{
|
||||
return '
|
||||
Envoi de SMS avec <a target="_blank" href="https://www.odyssey-messaging.com/">Odyssey Messaging</a>.
|
||||
Pour plus d\'information sur l\'utilisation de ce type de téléphone, reportez-vous à <a href="https://documentation.raspisms.fr/users/adapters/odyssey_messaging.html" target="_blank">la documentation sur le téléphone "Odyssey Messaging".</a>
|
||||
';
|
||||
}
|
||||
|
||||
/**
|
||||
* List of entries we want in data for the adapter.
|
||||
*
|
||||
* @return array : Every line is a field as an array with keys : name, title, description, required
|
||||
*/
|
||||
public static function meta_data_fields(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'name' => 'login',
|
||||
'title' => 'Odyssey login',
|
||||
'description' => 'Login du compte Odyssey à employer.',
|
||||
'required' => true,
|
||||
],
|
||||
[
|
||||
'name' => 'password',
|
||||
'title' => 'Mot de passe',
|
||||
'description' => 'Mot de passe du compte Odyssey à employer.',
|
||||
'required' => true,
|
||||
],
|
||||
[
|
||||
'name' => 'sender',
|
||||
'title' => 'Nom de l\'expéditeur',
|
||||
'description' => 'Nom de l\'expéditeur à afficher à la place du numéro (11 caractères max).<br/>
|
||||
<b>Laissez vide pour ne pas utiliser d\'expéditeur nommé.</b><br/>
|
||||
<b>Si vous utilisez un expéditeur nommé, le destinataire ne pourra pas répondre.</b>',
|
||||
'required' => false,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support reading smss.
|
||||
*/
|
||||
public static function meta_support_read(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support updating phone status.
|
||||
*/
|
||||
public static function meta_support_phone_status(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support flash smss.
|
||||
*/
|
||||
public static function meta_support_flash(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support status change.
|
||||
*/
|
||||
public static function meta_support_status_change(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support reception callback.
|
||||
*/
|
||||
public static function meta_support_reception(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support mms reception.
|
||||
*/
|
||||
public static function meta_support_mms_reception(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support mms sending.
|
||||
*/
|
||||
public static function meta_support_mms_sending(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function meta_support_inbound_call_callback(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function meta_support_end_call_callback(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function send(string $destination, string $text, bool $flash = false, bool $mms = false, array $medias = []): array
|
||||
{
|
||||
$response = [
|
||||
'error' => false,
|
||||
'error_message' => null,
|
||||
'uid' => null,
|
||||
];
|
||||
|
||||
try
|
||||
{
|
||||
$credentials = base64_encode($this->login . ':' . $this->password);
|
||||
$headers = [
|
||||
'Authorization: Basic ' . $credentials,
|
||||
'Content-Type: application/json',
|
||||
];
|
||||
|
||||
$data = [
|
||||
'JobType' => 'SMS',
|
||||
'Text' => $text,
|
||||
'TrackingID' => uniqid(),
|
||||
'AdhocRecipients' => [['Name' => uniqid(), 'Address' => str_replace('+', '00', $destination)]],
|
||||
];
|
||||
|
||||
if ($this->sender)
|
||||
{
|
||||
$data['Parameter'] = ['Sender' => $this->sender, 'Media' => 1];
|
||||
}
|
||||
|
||||
$data = json_encode($data);
|
||||
|
||||
$endpoint = $this->api_url . '/SMSJobs';
|
||||
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_URL, $endpoint);
|
||||
curl_setopt($curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
|
||||
curl_setopt($curl, CURLOPT_POST, true);
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
|
||||
$curl_response = curl_exec($curl);
|
||||
$http_code = (int) curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
curl_close($curl);
|
||||
|
||||
if (false === $curl_response)
|
||||
{
|
||||
$response['error'] = true;
|
||||
$response['error_message'] = 'HTTP query failed.';
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
$response_decode = json_decode($curl_response, true);
|
||||
if (null === $response_decode)
|
||||
{
|
||||
$response['error'] = true;
|
||||
$response['error_message'] = 'Invalid JSON for response.';
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
if (200 !== $http_code)
|
||||
{
|
||||
$response['error'] = true;
|
||||
$response['error_message'] = 'Response indicate error : ' . $response_decode['Message'] . ' -> """' . json_encode($response_decode['ModelState']) . '""" AND HTTP CODE -> ' . $http_code;
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
$uid = $response_decode['JobNumber'] ?? false;
|
||||
if (!$uid)
|
||||
{
|
||||
$response['error'] = true;
|
||||
$response['error_message'] = 'Cannot extract SMS uid';
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
$response['uid'] = $uid;
|
||||
|
||||
return $response;
|
||||
}
|
||||
catch (\Throwable $t)
|
||||
{
|
||||
$response['error'] = true;
|
||||
$response['error_message'] = $t->getMessage();
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
public function read(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called to verify phone status
|
||||
*
|
||||
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
|
||||
*/
|
||||
public function check_phone_status(): string
|
||||
{
|
||||
return \models\Phone::STATUS_AVAILABLE;
|
||||
}
|
||||
|
||||
public function test(): bool
|
||||
{
|
||||
try
|
||||
{
|
||||
if ($this->data['sender'] && (mb_strlen($this->data['sender']) < 3 || mb_strlen($this->data['sender'] > 11)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($this->data['sms_type']) && !in_array($this->data['sms_type'], ['premium', 'low cost']))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$credentials = base64_encode($this->login . ':' . $this->password);
|
||||
$headers = [
|
||||
'Authorization: Basic ' . $credentials,
|
||||
'Content-Type: application/json',
|
||||
];
|
||||
|
||||
//Check service name
|
||||
$endpoint = $this->api_url . '/JobTypes';
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_URL, $endpoint);
|
||||
curl_setopt($curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
$response = curl_exec($curl);
|
||||
$http_code = (int) curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
curl_close($curl);
|
||||
|
||||
if (200 !== $http_code)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (\Throwable $t)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function status_change_callback()
|
||||
{
|
||||
header('Connection: close');
|
||||
header('Content-Encoding: none');
|
||||
header('Content-Length: 0');
|
||||
|
||||
$input = file_get_contents('php://input');
|
||||
$content = json_decode($input, true);
|
||||
if (null === $content)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$event_type = $content['EventType'] ?? false;
|
||||
if ($event_type != self::EVENT_TYPES['ITEM_STATUS_CHANGED'])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$uid = $content['JobNumber'] ?? false;
|
||||
$status = $content['Outcome'] ?? false;
|
||||
|
||||
if (false === $uid || false === $status)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ($status)
|
||||
{
|
||||
case 'S':
|
||||
$status = \models\Sended::STATUS_DELIVERED;
|
||||
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
$status = \models\Sended::STATUS_UNKNOWN;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
$status = \models\Sended::STATUS_FAILED;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return ['uid' => $uid, 'status' => $status];
|
||||
}
|
||||
|
||||
public static function reception_callback(): array
|
||||
{
|
||||
$response = [
|
||||
'error' => false,
|
||||
'error_message' => null,
|
||||
'sms' => null,
|
||||
];
|
||||
|
||||
header('Connection: close');
|
||||
header('Content-Encoding: none');
|
||||
header('Content-Length: 0');
|
||||
|
||||
$input = file_get_contents('php://input');
|
||||
$content = json_decode($input, true);
|
||||
if (null === $content)
|
||||
{
|
||||
$response['error'] = true;
|
||||
$response['error_message'] = 'Cannot read input data from callback request.';
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
$event_type = $content['EventType'] ?? false;
|
||||
if ($event_type != self::EVENT_TYPES['INBOUND_SMS'])
|
||||
{
|
||||
$response['error'] = true;
|
||||
$response['error_message'] = 'Invalid event type : ' . $event_type . '.';
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
$number = $content['From'] ?? false;
|
||||
$text = $content['Message'] ?? false;
|
||||
$at = $content['EventDateTime'] ?? false;
|
||||
|
||||
if (!$number || !$text || !$at)
|
||||
{
|
||||
$response['error'] = true;
|
||||
$response['error_message'] = 'One required data of the callback is missing.';
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
$matches = null;
|
||||
$match = preg_match('#/Date\(([0-9]+)\+([0-9]+)\)/#', $at, $matches);
|
||||
$timestamp = ($matches[1] ?? null);
|
||||
if (!$match || !$timestamp)
|
||||
{
|
||||
$response['error'] = true;
|
||||
$response['error_message'] = 'Invalid date.';
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
$at = DateTime::createFromFormat('U', $timestamp / 1000);
|
||||
$at = $at->format('Y-m-d H:i:s');
|
||||
|
||||
$origin = \controllers\internals\Tool::parse_phone($number);
|
||||
if (!$origin)
|
||||
{
|
||||
$response['error'] = true;
|
||||
$response['error_message'] = 'Invalid origin number : ' . $number;
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
$response['sms'] = [
|
||||
'at' => $at,
|
||||
'text' => $text,
|
||||
'origin' => $origin,
|
||||
];
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function inbound_call_callback(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function end_call_callback(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
|
@ -162,6 +162,14 @@ namespace adapters;
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support updating phone status.
|
||||
*/
|
||||
public static function meta_support_phone_status(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support flash smss.
|
||||
*/
|
||||
|
|
@ -327,6 +335,16 @@ namespace adapters;
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called to verify phone status
|
||||
*
|
||||
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
|
||||
*/
|
||||
public function check_phone_status(): string
|
||||
{
|
||||
return \models\Phone::STATUS_AVAILABLE;
|
||||
}
|
||||
|
||||
public function test(): bool
|
||||
{
|
||||
try
|
||||
|
|
|
|||
|
|
@ -166,6 +166,14 @@ namespace adapters;
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support updating phone status.
|
||||
*/
|
||||
public static function meta_support_phone_status(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support flash smss.
|
||||
*/
|
||||
|
|
@ -317,6 +325,16 @@ namespace adapters;
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called to verify phone status
|
||||
*
|
||||
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
|
||||
*/
|
||||
public function check_phone_status(): string
|
||||
{
|
||||
return \models\Phone::STATUS_AVAILABLE;
|
||||
}
|
||||
|
||||
public function test(): bool
|
||||
{
|
||||
try
|
||||
|
|
|
|||
|
|
@ -116,6 +116,14 @@ namespace adapters;
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support updating phone status.
|
||||
*/
|
||||
public static function meta_support_phone_status(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support flash smss.
|
||||
*/
|
||||
|
|
@ -287,6 +295,16 @@ namespace adapters;
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called to verify phone status
|
||||
*
|
||||
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
|
||||
*/
|
||||
public function check_phone_status(): string
|
||||
{
|
||||
return \models\Phone::STATUS_AVAILABLE;
|
||||
}
|
||||
|
||||
public function test(): bool
|
||||
{
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -160,6 +160,14 @@ class TwilioVirtualNumberAdapter implements AdapterInterface
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support updating phone status.
|
||||
*/
|
||||
public static function meta_support_phone_status(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the implemented service support flash smss.
|
||||
*/
|
||||
|
|
@ -295,6 +303,16 @@ class TwilioVirtualNumberAdapter implements AdapterInterface
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called to verify phone status
|
||||
*
|
||||
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
|
||||
*/
|
||||
public function check_phone_status(): string
|
||||
{
|
||||
return \models\Phone::STATUS_AVAILABLE;
|
||||
}
|
||||
|
||||
public function test(): bool
|
||||
{
|
||||
try
|
||||
|
|
|
|||
685
assets/font/fonts-awesome/css/font-awesome.css
vendored
685
assets/font/fonts-awesome/css/font-awesome.css
vendored
|
|
@ -1,13 +1,13 @@
|
|||
/*!
|
||||
* Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome
|
||||
* Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
|
||||
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
|
||||
*/
|
||||
/* FONT PATH
|
||||
* -------------------------- */
|
||||
@font-face {
|
||||
font-family: 'FontAwesome';
|
||||
src: url('../fonts/fontawesome-webfont.eot?v=4.2.0');
|
||||
src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.2.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff?v=4.2.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.2.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular') format('svg');
|
||||
src: url('../fonts/fontawesome-webfont.eot?v=4.7.0');
|
||||
src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
|
@ -64,6 +64,19 @@
|
|||
border: solid 0.08em #eeeeee;
|
||||
border-radius: .1em;
|
||||
}
|
||||
.fa-pull-left {
|
||||
float: left;
|
||||
}
|
||||
.fa-pull-right {
|
||||
float: right;
|
||||
}
|
||||
.fa.fa-pull-left {
|
||||
margin-right: .3em;
|
||||
}
|
||||
.fa.fa-pull-right {
|
||||
margin-left: .3em;
|
||||
}
|
||||
/* Deprecated as of 4.4.0 */
|
||||
.pull-right {
|
||||
float: right;
|
||||
}
|
||||
|
|
@ -80,6 +93,10 @@
|
|||
-webkit-animation: fa-spin 2s infinite linear;
|
||||
animation: fa-spin 2s infinite linear;
|
||||
}
|
||||
.fa-pulse {
|
||||
-webkit-animation: fa-spin 1s infinite steps(8);
|
||||
animation: fa-spin 1s infinite steps(8);
|
||||
}
|
||||
@-webkit-keyframes fa-spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
|
|
@ -101,31 +118,31 @@
|
|||
}
|
||||
}
|
||||
.fa-rotate-90 {
|
||||
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";
|
||||
-webkit-transform: rotate(90deg);
|
||||
-ms-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
.fa-rotate-180 {
|
||||
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";
|
||||
-webkit-transform: rotate(180deg);
|
||||
-ms-transform: rotate(180deg);
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
.fa-rotate-270 {
|
||||
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";
|
||||
-webkit-transform: rotate(270deg);
|
||||
-ms-transform: rotate(270deg);
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
.fa-flip-horizontal {
|
||||
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";
|
||||
-webkit-transform: scale(-1, 1);
|
||||
-ms-transform: scale(-1, 1);
|
||||
transform: scale(-1, 1);
|
||||
}
|
||||
.fa-flip-vertical {
|
||||
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";
|
||||
-webkit-transform: scale(1, -1);
|
||||
-ms-transform: scale(1, -1);
|
||||
transform: scale(1, -1);
|
||||
|
|
@ -610,6 +627,7 @@
|
|||
.fa-twitter:before {
|
||||
content: "\f099";
|
||||
}
|
||||
.fa-facebook-f:before,
|
||||
.fa-facebook:before {
|
||||
content: "\f09a";
|
||||
}
|
||||
|
|
@ -622,6 +640,7 @@
|
|||
.fa-credit-card:before {
|
||||
content: "\f09d";
|
||||
}
|
||||
.fa-feed:before,
|
||||
.fa-rss:before {
|
||||
content: "\f09e";
|
||||
}
|
||||
|
|
@ -1259,7 +1278,8 @@
|
|||
.fa-male:before {
|
||||
content: "\f183";
|
||||
}
|
||||
.fa-gittip:before {
|
||||
.fa-gittip:before,
|
||||
.fa-gratipay:before {
|
||||
content: "\f184";
|
||||
}
|
||||
.fa-sun-o:before {
|
||||
|
|
@ -1363,7 +1383,7 @@
|
|||
.fa-digg:before {
|
||||
content: "\f1a6";
|
||||
}
|
||||
.fa-pied-piper:before {
|
||||
.fa-pied-piper-pp:before {
|
||||
content: "\f1a7";
|
||||
}
|
||||
.fa-pied-piper-alt:before {
|
||||
|
|
@ -1489,6 +1509,7 @@
|
|||
content: "\f1ce";
|
||||
}
|
||||
.fa-ra:before,
|
||||
.fa-resistance:before,
|
||||
.fa-rebel:before {
|
||||
content: "\f1d0";
|
||||
}
|
||||
|
|
@ -1502,6 +1523,8 @@
|
|||
.fa-git:before {
|
||||
content: "\f1d3";
|
||||
}
|
||||
.fa-y-combinator-square:before,
|
||||
.fa-yc-square:before,
|
||||
.fa-hacker-news:before {
|
||||
content: "\f1d4";
|
||||
}
|
||||
|
|
@ -1670,3 +1693,645 @@
|
|||
.fa-meanpath:before {
|
||||
content: "\f20c";
|
||||
}
|
||||
.fa-buysellads:before {
|
||||
content: "\f20d";
|
||||
}
|
||||
.fa-connectdevelop:before {
|
||||
content: "\f20e";
|
||||
}
|
||||
.fa-dashcube:before {
|
||||
content: "\f210";
|
||||
}
|
||||
.fa-forumbee:before {
|
||||
content: "\f211";
|
||||
}
|
||||
.fa-leanpub:before {
|
||||
content: "\f212";
|
||||
}
|
||||
.fa-sellsy:before {
|
||||
content: "\f213";
|
||||
}
|
||||
.fa-shirtsinbulk:before {
|
||||
content: "\f214";
|
||||
}
|
||||
.fa-simplybuilt:before {
|
||||
content: "\f215";
|
||||
}
|
||||
.fa-skyatlas:before {
|
||||
content: "\f216";
|
||||
}
|
||||
.fa-cart-plus:before {
|
||||
content: "\f217";
|
||||
}
|
||||
.fa-cart-arrow-down:before {
|
||||
content: "\f218";
|
||||
}
|
||||
.fa-diamond:before {
|
||||
content: "\f219";
|
||||
}
|
||||
.fa-ship:before {
|
||||
content: "\f21a";
|
||||
}
|
||||
.fa-user-secret:before {
|
||||
content: "\f21b";
|
||||
}
|
||||
.fa-motorcycle:before {
|
||||
content: "\f21c";
|
||||
}
|
||||
.fa-street-view:before {
|
||||
content: "\f21d";
|
||||
}
|
||||
.fa-heartbeat:before {
|
||||
content: "\f21e";
|
||||
}
|
||||
.fa-venus:before {
|
||||
content: "\f221";
|
||||
}
|
||||
.fa-mars:before {
|
||||
content: "\f222";
|
||||
}
|
||||
.fa-mercury:before {
|
||||
content: "\f223";
|
||||
}
|
||||
.fa-intersex:before,
|
||||
.fa-transgender:before {
|
||||
content: "\f224";
|
||||
}
|
||||
.fa-transgender-alt:before {
|
||||
content: "\f225";
|
||||
}
|
||||
.fa-venus-double:before {
|
||||
content: "\f226";
|
||||
}
|
||||
.fa-mars-double:before {
|
||||
content: "\f227";
|
||||
}
|
||||
.fa-venus-mars:before {
|
||||
content: "\f228";
|
||||
}
|
||||
.fa-mars-stroke:before {
|
||||
content: "\f229";
|
||||
}
|
||||
.fa-mars-stroke-v:before {
|
||||
content: "\f22a";
|
||||
}
|
||||
.fa-mars-stroke-h:before {
|
||||
content: "\f22b";
|
||||
}
|
||||
.fa-neuter:before {
|
||||
content: "\f22c";
|
||||
}
|
||||
.fa-genderless:before {
|
||||
content: "\f22d";
|
||||
}
|
||||
.fa-facebook-official:before {
|
||||
content: "\f230";
|
||||
}
|
||||
.fa-pinterest-p:before {
|
||||
content: "\f231";
|
||||
}
|
||||
.fa-whatsapp:before {
|
||||
content: "\f232";
|
||||
}
|
||||
.fa-server:before {
|
||||
content: "\f233";
|
||||
}
|
||||
.fa-user-plus:before {
|
||||
content: "\f234";
|
||||
}
|
||||
.fa-user-times:before {
|
||||
content: "\f235";
|
||||
}
|
||||
.fa-hotel:before,
|
||||
.fa-bed:before {
|
||||
content: "\f236";
|
||||
}
|
||||
.fa-viacoin:before {
|
||||
content: "\f237";
|
||||
}
|
||||
.fa-train:before {
|
||||
content: "\f238";
|
||||
}
|
||||
.fa-subway:before {
|
||||
content: "\f239";
|
||||
}
|
||||
.fa-medium:before {
|
||||
content: "\f23a";
|
||||
}
|
||||
.fa-yc:before,
|
||||
.fa-y-combinator:before {
|
||||
content: "\f23b";
|
||||
}
|
||||
.fa-optin-monster:before {
|
||||
content: "\f23c";
|
||||
}
|
||||
.fa-opencart:before {
|
||||
content: "\f23d";
|
||||
}
|
||||
.fa-expeditedssl:before {
|
||||
content: "\f23e";
|
||||
}
|
||||
.fa-battery-4:before,
|
||||
.fa-battery:before,
|
||||
.fa-battery-full:before {
|
||||
content: "\f240";
|
||||
}
|
||||
.fa-battery-3:before,
|
||||
.fa-battery-three-quarters:before {
|
||||
content: "\f241";
|
||||
}
|
||||
.fa-battery-2:before,
|
||||
.fa-battery-half:before {
|
||||
content: "\f242";
|
||||
}
|
||||
.fa-battery-1:before,
|
||||
.fa-battery-quarter:before {
|
||||
content: "\f243";
|
||||
}
|
||||
.fa-battery-0:before,
|
||||
.fa-battery-empty:before {
|
||||
content: "\f244";
|
||||
}
|
||||
.fa-mouse-pointer:before {
|
||||
content: "\f245";
|
||||
}
|
||||
.fa-i-cursor:before {
|
||||
content: "\f246";
|
||||
}
|
||||
.fa-object-group:before {
|
||||
content: "\f247";
|
||||
}
|
||||
.fa-object-ungroup:before {
|
||||
content: "\f248";
|
||||
}
|
||||
.fa-sticky-note:before {
|
||||
content: "\f249";
|
||||
}
|
||||
.fa-sticky-note-o:before {
|
||||
content: "\f24a";
|
||||
}
|
||||
.fa-cc-jcb:before {
|
||||
content: "\f24b";
|
||||
}
|
||||
.fa-cc-diners-club:before {
|
||||
content: "\f24c";
|
||||
}
|
||||
.fa-clone:before {
|
||||
content: "\f24d";
|
||||
}
|
||||
.fa-balance-scale:before {
|
||||
content: "\f24e";
|
||||
}
|
||||
.fa-hourglass-o:before {
|
||||
content: "\f250";
|
||||
}
|
||||
.fa-hourglass-1:before,
|
||||
.fa-hourglass-start:before {
|
||||
content: "\f251";
|
||||
}
|
||||
.fa-hourglass-2:before,
|
||||
.fa-hourglass-half:before {
|
||||
content: "\f252";
|
||||
}
|
||||
.fa-hourglass-3:before,
|
||||
.fa-hourglass-end:before {
|
||||
content: "\f253";
|
||||
}
|
||||
.fa-hourglass:before {
|
||||
content: "\f254";
|
||||
}
|
||||
.fa-hand-grab-o:before,
|
||||
.fa-hand-rock-o:before {
|
||||
content: "\f255";
|
||||
}
|
||||
.fa-hand-stop-o:before,
|
||||
.fa-hand-paper-o:before {
|
||||
content: "\f256";
|
||||
}
|
||||
.fa-hand-scissors-o:before {
|
||||
content: "\f257";
|
||||
}
|
||||
.fa-hand-lizard-o:before {
|
||||
content: "\f258";
|
||||
}
|
||||
.fa-hand-spock-o:before {
|
||||
content: "\f259";
|
||||
}
|
||||
.fa-hand-pointer-o:before {
|
||||
content: "\f25a";
|
||||
}
|
||||
.fa-hand-peace-o:before {
|
||||
content: "\f25b";
|
||||
}
|
||||
.fa-trademark:before {
|
||||
content: "\f25c";
|
||||
}
|
||||
.fa-registered:before {
|
||||
content: "\f25d";
|
||||
}
|
||||
.fa-creative-commons:before {
|
||||
content: "\f25e";
|
||||
}
|
||||
.fa-gg:before {
|
||||
content: "\f260";
|
||||
}
|
||||
.fa-gg-circle:before {
|
||||
content: "\f261";
|
||||
}
|
||||
.fa-tripadvisor:before {
|
||||
content: "\f262";
|
||||
}
|
||||
.fa-odnoklassniki:before {
|
||||
content: "\f263";
|
||||
}
|
||||
.fa-odnoklassniki-square:before {
|
||||
content: "\f264";
|
||||
}
|
||||
.fa-get-pocket:before {
|
||||
content: "\f265";
|
||||
}
|
||||
.fa-wikipedia-w:before {
|
||||
content: "\f266";
|
||||
}
|
||||
.fa-safari:before {
|
||||
content: "\f267";
|
||||
}
|
||||
.fa-chrome:before {
|
||||
content: "\f268";
|
||||
}
|
||||
.fa-firefox:before {
|
||||
content: "\f269";
|
||||
}
|
||||
.fa-opera:before {
|
||||
content: "\f26a";
|
||||
}
|
||||
.fa-internet-explorer:before {
|
||||
content: "\f26b";
|
||||
}
|
||||
.fa-tv:before,
|
||||
.fa-television:before {
|
||||
content: "\f26c";
|
||||
}
|
||||
.fa-contao:before {
|
||||
content: "\f26d";
|
||||
}
|
||||
.fa-500px:before {
|
||||
content: "\f26e";
|
||||
}
|
||||
.fa-amazon:before {
|
||||
content: "\f270";
|
||||
}
|
||||
.fa-calendar-plus-o:before {
|
||||
content: "\f271";
|
||||
}
|
||||
.fa-calendar-minus-o:before {
|
||||
content: "\f272";
|
||||
}
|
||||
.fa-calendar-times-o:before {
|
||||
content: "\f273";
|
||||
}
|
||||
.fa-calendar-check-o:before {
|
||||
content: "\f274";
|
||||
}
|
||||
.fa-industry:before {
|
||||
content: "\f275";
|
||||
}
|
||||
.fa-map-pin:before {
|
||||
content: "\f276";
|
||||
}
|
||||
.fa-map-signs:before {
|
||||
content: "\f277";
|
||||
}
|
||||
.fa-map-o:before {
|
||||
content: "\f278";
|
||||
}
|
||||
.fa-map:before {
|
||||
content: "\f279";
|
||||
}
|
||||
.fa-commenting:before {
|
||||
content: "\f27a";
|
||||
}
|
||||
.fa-commenting-o:before {
|
||||
content: "\f27b";
|
||||
}
|
||||
.fa-houzz:before {
|
||||
content: "\f27c";
|
||||
}
|
||||
.fa-vimeo:before {
|
||||
content: "\f27d";
|
||||
}
|
||||
.fa-black-tie:before {
|
||||
content: "\f27e";
|
||||
}
|
||||
.fa-fonticons:before {
|
||||
content: "\f280";
|
||||
}
|
||||
.fa-reddit-alien:before {
|
||||
content: "\f281";
|
||||
}
|
||||
.fa-edge:before {
|
||||
content: "\f282";
|
||||
}
|
||||
.fa-credit-card-alt:before {
|
||||
content: "\f283";
|
||||
}
|
||||
.fa-codiepie:before {
|
||||
content: "\f284";
|
||||
}
|
||||
.fa-modx:before {
|
||||
content: "\f285";
|
||||
}
|
||||
.fa-fort-awesome:before {
|
||||
content: "\f286";
|
||||
}
|
||||
.fa-usb:before {
|
||||
content: "\f287";
|
||||
}
|
||||
.fa-product-hunt:before {
|
||||
content: "\f288";
|
||||
}
|
||||
.fa-mixcloud:before {
|
||||
content: "\f289";
|
||||
}
|
||||
.fa-scribd:before {
|
||||
content: "\f28a";
|
||||
}
|
||||
.fa-pause-circle:before {
|
||||
content: "\f28b";
|
||||
}
|
||||
.fa-pause-circle-o:before {
|
||||
content: "\f28c";
|
||||
}
|
||||
.fa-stop-circle:before {
|
||||
content: "\f28d";
|
||||
}
|
||||
.fa-stop-circle-o:before {
|
||||
content: "\f28e";
|
||||
}
|
||||
.fa-shopping-bag:before {
|
||||
content: "\f290";
|
||||
}
|
||||
.fa-shopping-basket:before {
|
||||
content: "\f291";
|
||||
}
|
||||
.fa-hashtag:before {
|
||||
content: "\f292";
|
||||
}
|
||||
.fa-bluetooth:before {
|
||||
content: "\f293";
|
||||
}
|
||||
.fa-bluetooth-b:before {
|
||||
content: "\f294";
|
||||
}
|
||||
.fa-percent:before {
|
||||
content: "\f295";
|
||||
}
|
||||
.fa-gitlab:before {
|
||||
content: "\f296";
|
||||
}
|
||||
.fa-wpbeginner:before {
|
||||
content: "\f297";
|
||||
}
|
||||
.fa-wpforms:before {
|
||||
content: "\f298";
|
||||
}
|
||||
.fa-envira:before {
|
||||
content: "\f299";
|
||||
}
|
||||
.fa-universal-access:before {
|
||||
content: "\f29a";
|
||||
}
|
||||
.fa-wheelchair-alt:before {
|
||||
content: "\f29b";
|
||||
}
|
||||
.fa-question-circle-o:before {
|
||||
content: "\f29c";
|
||||
}
|
||||
.fa-blind:before {
|
||||
content: "\f29d";
|
||||
}
|
||||
.fa-audio-description:before {
|
||||
content: "\f29e";
|
||||
}
|
||||
.fa-volume-control-phone:before {
|
||||
content: "\f2a0";
|
||||
}
|
||||
.fa-braille:before {
|
||||
content: "\f2a1";
|
||||
}
|
||||
.fa-assistive-listening-systems:before {
|
||||
content: "\f2a2";
|
||||
}
|
||||
.fa-asl-interpreting:before,
|
||||
.fa-american-sign-language-interpreting:before {
|
||||
content: "\f2a3";
|
||||
}
|
||||
.fa-deafness:before,
|
||||
.fa-hard-of-hearing:before,
|
||||
.fa-deaf:before {
|
||||
content: "\f2a4";
|
||||
}
|
||||
.fa-glide:before {
|
||||
content: "\f2a5";
|
||||
}
|
||||
.fa-glide-g:before {
|
||||
content: "\f2a6";
|
||||
}
|
||||
.fa-signing:before,
|
||||
.fa-sign-language:before {
|
||||
content: "\f2a7";
|
||||
}
|
||||
.fa-low-vision:before {
|
||||
content: "\f2a8";
|
||||
}
|
||||
.fa-viadeo:before {
|
||||
content: "\f2a9";
|
||||
}
|
||||
.fa-viadeo-square:before {
|
||||
content: "\f2aa";
|
||||
}
|
||||
.fa-snapchat:before {
|
||||
content: "\f2ab";
|
||||
}
|
||||
.fa-snapchat-ghost:before {
|
||||
content: "\f2ac";
|
||||
}
|
||||
.fa-snapchat-square:before {
|
||||
content: "\f2ad";
|
||||
}
|
||||
.fa-pied-piper:before {
|
||||
content: "\f2ae";
|
||||
}
|
||||
.fa-first-order:before {
|
||||
content: "\f2b0";
|
||||
}
|
||||
.fa-yoast:before {
|
||||
content: "\f2b1";
|
||||
}
|
||||
.fa-themeisle:before {
|
||||
content: "\f2b2";
|
||||
}
|
||||
.fa-google-plus-circle:before,
|
||||
.fa-google-plus-official:before {
|
||||
content: "\f2b3";
|
||||
}
|
||||
.fa-fa:before,
|
||||
.fa-font-awesome:before {
|
||||
content: "\f2b4";
|
||||
}
|
||||
.fa-handshake-o:before {
|
||||
content: "\f2b5";
|
||||
}
|
||||
.fa-envelope-open:before {
|
||||
content: "\f2b6";
|
||||
}
|
||||
.fa-envelope-open-o:before {
|
||||
content: "\f2b7";
|
||||
}
|
||||
.fa-linode:before {
|
||||
content: "\f2b8";
|
||||
}
|
||||
.fa-address-book:before {
|
||||
content: "\f2b9";
|
||||
}
|
||||
.fa-address-book-o:before {
|
||||
content: "\f2ba";
|
||||
}
|
||||
.fa-vcard:before,
|
||||
.fa-address-card:before {
|
||||
content: "\f2bb";
|
||||
}
|
||||
.fa-vcard-o:before,
|
||||
.fa-address-card-o:before {
|
||||
content: "\f2bc";
|
||||
}
|
||||
.fa-user-circle:before {
|
||||
content: "\f2bd";
|
||||
}
|
||||
.fa-user-circle-o:before {
|
||||
content: "\f2be";
|
||||
}
|
||||
.fa-user-o:before {
|
||||
content: "\f2c0";
|
||||
}
|
||||
.fa-id-badge:before {
|
||||
content: "\f2c1";
|
||||
}
|
||||
.fa-drivers-license:before,
|
||||
.fa-id-card:before {
|
||||
content: "\f2c2";
|
||||
}
|
||||
.fa-drivers-license-o:before,
|
||||
.fa-id-card-o:before {
|
||||
content: "\f2c3";
|
||||
}
|
||||
.fa-quora:before {
|
||||
content: "\f2c4";
|
||||
}
|
||||
.fa-free-code-camp:before {
|
||||
content: "\f2c5";
|
||||
}
|
||||
.fa-telegram:before {
|
||||
content: "\f2c6";
|
||||
}
|
||||
.fa-thermometer-4:before,
|
||||
.fa-thermometer:before,
|
||||
.fa-thermometer-full:before {
|
||||
content: "\f2c7";
|
||||
}
|
||||
.fa-thermometer-3:before,
|
||||
.fa-thermometer-three-quarters:before {
|
||||
content: "\f2c8";
|
||||
}
|
||||
.fa-thermometer-2:before,
|
||||
.fa-thermometer-half:before {
|
||||
content: "\f2c9";
|
||||
}
|
||||
.fa-thermometer-1:before,
|
||||
.fa-thermometer-quarter:before {
|
||||
content: "\f2ca";
|
||||
}
|
||||
.fa-thermometer-0:before,
|
||||
.fa-thermometer-empty:before {
|
||||
content: "\f2cb";
|
||||
}
|
||||
.fa-shower:before {
|
||||
content: "\f2cc";
|
||||
}
|
||||
.fa-bathtub:before,
|
||||
.fa-s15:before,
|
||||
.fa-bath:before {
|
||||
content: "\f2cd";
|
||||
}
|
||||
.fa-podcast:before {
|
||||
content: "\f2ce";
|
||||
}
|
||||
.fa-window-maximize:before {
|
||||
content: "\f2d0";
|
||||
}
|
||||
.fa-window-minimize:before {
|
||||
content: "\f2d1";
|
||||
}
|
||||
.fa-window-restore:before {
|
||||
content: "\f2d2";
|
||||
}
|
||||
.fa-times-rectangle:before,
|
||||
.fa-window-close:before {
|
||||
content: "\f2d3";
|
||||
}
|
||||
.fa-times-rectangle-o:before,
|
||||
.fa-window-close-o:before {
|
||||
content: "\f2d4";
|
||||
}
|
||||
.fa-bandcamp:before {
|
||||
content: "\f2d5";
|
||||
}
|
||||
.fa-grav:before {
|
||||
content: "\f2d6";
|
||||
}
|
||||
.fa-etsy:before {
|
||||
content: "\f2d7";
|
||||
}
|
||||
.fa-imdb:before {
|
||||
content: "\f2d8";
|
||||
}
|
||||
.fa-ravelry:before {
|
||||
content: "\f2d9";
|
||||
}
|
||||
.fa-eercast:before {
|
||||
content: "\f2da";
|
||||
}
|
||||
.fa-microchip:before {
|
||||
content: "\f2db";
|
||||
}
|
||||
.fa-snowflake-o:before {
|
||||
content: "\f2dc";
|
||||
}
|
||||
.fa-superpowers:before {
|
||||
content: "\f2dd";
|
||||
}
|
||||
.fa-wpexplorer:before {
|
||||
content: "\f2de";
|
||||
}
|
||||
.fa-meetup:before {
|
||||
content: "\f2e0";
|
||||
}
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
border: 0;
|
||||
}
|
||||
.sr-only-focusable:active,
|
||||
.sr-only-focusable:focus {
|
||||
position: static;
|
||||
width: auto;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
overflow: visible;
|
||||
clip: auto;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
Before Width: | Height: | Size: 280 KiB After Width: | Height: | Size: 434 KiB |
Binary file not shown.
Binary file not shown.
BIN
assets/font/fonts-awesome/fonts/fontawesome-webfont.woff2
Normal file
BIN
assets/font/fonts-awesome/fonts/fontawesome-webfont.woff2
Normal file
Binary file not shown.
|
|
@ -1,4 +1,4 @@
|
|||
// Spinning Icons
|
||||
// Animated Icons
|
||||
// --------------------------
|
||||
|
||||
.@{fa-css-prefix}-spin {
|
||||
|
|
@ -6,6 +6,11 @@
|
|||
animation: fa-spin 2s infinite linear;
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-pulse {
|
||||
-webkit-animation: fa-spin 1s infinite steps(8);
|
||||
animation: fa-spin 1s infinite steps(8);
|
||||
}
|
||||
|
||||
@-webkit-keyframes fa-spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
|
|
@ -7,6 +7,15 @@
|
|||
border-radius: .1em;
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-pull-left { float: left; }
|
||||
.@{fa-css-prefix}-pull-right { float: right; }
|
||||
|
||||
.@{fa-css-prefix} {
|
||||
&.@{fa-css-prefix}-pull-left { margin-right: .3em; }
|
||||
&.@{fa-css-prefix}-pull-right { margin-left: .3em; }
|
||||
}
|
||||
|
||||
/* Deprecated as of 4.4.0 */
|
||||
.pull-right { float: right; }
|
||||
.pull-left { float: left; }
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,10 @@
|
|||
|
||||
.@{fa-css-prefix} {
|
||||
display: inline-block;
|
||||
font: normal normal normal 14px/1 FontAwesome; // shortening font declaration
|
||||
font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
|
||||
font-size: inherit; // can't have font-size inherit on line above, so need to override
|
||||
text-rendering: auto; // optimizelegibility throws things off #1094
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*!
|
||||
* Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome
|
||||
* Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
|
||||
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
|
||||
*/
|
||||
|
||||
|
|
@ -11,7 +11,8 @@
|
|||
@import "fixed-width.less";
|
||||
@import "list.less";
|
||||
@import "bordered-pulled.less";
|
||||
@import "spinning.less";
|
||||
@import "animated.less";
|
||||
@import "rotated-flipped.less";
|
||||
@import "stacked.less";
|
||||
@import "icons.less";
|
||||
@import "screen-reader.less";
|
||||
|
|
|
|||
|
|
@ -158,10 +158,12 @@
|
|||
.@{fa-css-prefix}-bookmark-o:before { content: @fa-var-bookmark-o; }
|
||||
.@{fa-css-prefix}-phone-square:before { content: @fa-var-phone-square; }
|
||||
.@{fa-css-prefix}-twitter:before { content: @fa-var-twitter; }
|
||||
.@{fa-css-prefix}-facebook-f:before,
|
||||
.@{fa-css-prefix}-facebook:before { content: @fa-var-facebook; }
|
||||
.@{fa-css-prefix}-github:before { content: @fa-var-github; }
|
||||
.@{fa-css-prefix}-unlock:before { content: @fa-var-unlock; }
|
||||
.@{fa-css-prefix}-credit-card:before { content: @fa-var-credit-card; }
|
||||
.@{fa-css-prefix}-feed:before,
|
||||
.@{fa-css-prefix}-rss:before { content: @fa-var-rss; }
|
||||
.@{fa-css-prefix}-hdd-o:before { content: @fa-var-hdd-o; }
|
||||
.@{fa-css-prefix}-bullhorn:before { content: @fa-var-bullhorn; }
|
||||
|
|
@ -397,7 +399,8 @@
|
|||
.@{fa-css-prefix}-trello:before { content: @fa-var-trello; }
|
||||
.@{fa-css-prefix}-female:before { content: @fa-var-female; }
|
||||
.@{fa-css-prefix}-male:before { content: @fa-var-male; }
|
||||
.@{fa-css-prefix}-gittip:before { content: @fa-var-gittip; }
|
||||
.@{fa-css-prefix}-gittip:before,
|
||||
.@{fa-css-prefix}-gratipay:before { content: @fa-var-gratipay; }
|
||||
.@{fa-css-prefix}-sun-o:before { content: @fa-var-sun-o; }
|
||||
.@{fa-css-prefix}-moon-o:before { content: @fa-var-moon-o; }
|
||||
.@{fa-css-prefix}-archive:before { content: @fa-var-archive; }
|
||||
|
|
@ -435,7 +438,7 @@
|
|||
.@{fa-css-prefix}-stumbleupon:before { content: @fa-var-stumbleupon; }
|
||||
.@{fa-css-prefix}-delicious:before { content: @fa-var-delicious; }
|
||||
.@{fa-css-prefix}-digg:before { content: @fa-var-digg; }
|
||||
.@{fa-css-prefix}-pied-piper:before { content: @fa-var-pied-piper; }
|
||||
.@{fa-css-prefix}-pied-piper-pp:before { content: @fa-var-pied-piper-pp; }
|
||||
.@{fa-css-prefix}-pied-piper-alt:before { content: @fa-var-pied-piper-alt; }
|
||||
.@{fa-css-prefix}-drupal:before { content: @fa-var-drupal; }
|
||||
.@{fa-css-prefix}-joomla:before { content: @fa-var-joomla; }
|
||||
|
|
@ -485,11 +488,14 @@
|
|||
.@{fa-css-prefix}-life-ring:before { content: @fa-var-life-ring; }
|
||||
.@{fa-css-prefix}-circle-o-notch:before { content: @fa-var-circle-o-notch; }
|
||||
.@{fa-css-prefix}-ra:before,
|
||||
.@{fa-css-prefix}-resistance:before,
|
||||
.@{fa-css-prefix}-rebel:before { content: @fa-var-rebel; }
|
||||
.@{fa-css-prefix}-ge:before,
|
||||
.@{fa-css-prefix}-empire:before { content: @fa-var-empire; }
|
||||
.@{fa-css-prefix}-git-square:before { content: @fa-var-git-square; }
|
||||
.@{fa-css-prefix}-git:before { content: @fa-var-git; }
|
||||
.@{fa-css-prefix}-y-combinator-square:before,
|
||||
.@{fa-css-prefix}-yc-square:before,
|
||||
.@{fa-css-prefix}-hacker-news:before { content: @fa-var-hacker-news; }
|
||||
.@{fa-css-prefix}-tencent-weibo:before { content: @fa-var-tencent-weibo; }
|
||||
.@{fa-css-prefix}-qq:before { content: @fa-var-qq; }
|
||||
|
|
@ -550,3 +556,234 @@
|
|||
.@{fa-css-prefix}-sheqel:before,
|
||||
.@{fa-css-prefix}-ils:before { content: @fa-var-ils; }
|
||||
.@{fa-css-prefix}-meanpath:before { content: @fa-var-meanpath; }
|
||||
.@{fa-css-prefix}-buysellads:before { content: @fa-var-buysellads; }
|
||||
.@{fa-css-prefix}-connectdevelop:before { content: @fa-var-connectdevelop; }
|
||||
.@{fa-css-prefix}-dashcube:before { content: @fa-var-dashcube; }
|
||||
.@{fa-css-prefix}-forumbee:before { content: @fa-var-forumbee; }
|
||||
.@{fa-css-prefix}-leanpub:before { content: @fa-var-leanpub; }
|
||||
.@{fa-css-prefix}-sellsy:before { content: @fa-var-sellsy; }
|
||||
.@{fa-css-prefix}-shirtsinbulk:before { content: @fa-var-shirtsinbulk; }
|
||||
.@{fa-css-prefix}-simplybuilt:before { content: @fa-var-simplybuilt; }
|
||||
.@{fa-css-prefix}-skyatlas:before { content: @fa-var-skyatlas; }
|
||||
.@{fa-css-prefix}-cart-plus:before { content: @fa-var-cart-plus; }
|
||||
.@{fa-css-prefix}-cart-arrow-down:before { content: @fa-var-cart-arrow-down; }
|
||||
.@{fa-css-prefix}-diamond:before { content: @fa-var-diamond; }
|
||||
.@{fa-css-prefix}-ship:before { content: @fa-var-ship; }
|
||||
.@{fa-css-prefix}-user-secret:before { content: @fa-var-user-secret; }
|
||||
.@{fa-css-prefix}-motorcycle:before { content: @fa-var-motorcycle; }
|
||||
.@{fa-css-prefix}-street-view:before { content: @fa-var-street-view; }
|
||||
.@{fa-css-prefix}-heartbeat:before { content: @fa-var-heartbeat; }
|
||||
.@{fa-css-prefix}-venus:before { content: @fa-var-venus; }
|
||||
.@{fa-css-prefix}-mars:before { content: @fa-var-mars; }
|
||||
.@{fa-css-prefix}-mercury:before { content: @fa-var-mercury; }
|
||||
.@{fa-css-prefix}-intersex:before,
|
||||
.@{fa-css-prefix}-transgender:before { content: @fa-var-transgender; }
|
||||
.@{fa-css-prefix}-transgender-alt:before { content: @fa-var-transgender-alt; }
|
||||
.@{fa-css-prefix}-venus-double:before { content: @fa-var-venus-double; }
|
||||
.@{fa-css-prefix}-mars-double:before { content: @fa-var-mars-double; }
|
||||
.@{fa-css-prefix}-venus-mars:before { content: @fa-var-venus-mars; }
|
||||
.@{fa-css-prefix}-mars-stroke:before { content: @fa-var-mars-stroke; }
|
||||
.@{fa-css-prefix}-mars-stroke-v:before { content: @fa-var-mars-stroke-v; }
|
||||
.@{fa-css-prefix}-mars-stroke-h:before { content: @fa-var-mars-stroke-h; }
|
||||
.@{fa-css-prefix}-neuter:before { content: @fa-var-neuter; }
|
||||
.@{fa-css-prefix}-genderless:before { content: @fa-var-genderless; }
|
||||
.@{fa-css-prefix}-facebook-official:before { content: @fa-var-facebook-official; }
|
||||
.@{fa-css-prefix}-pinterest-p:before { content: @fa-var-pinterest-p; }
|
||||
.@{fa-css-prefix}-whatsapp:before { content: @fa-var-whatsapp; }
|
||||
.@{fa-css-prefix}-server:before { content: @fa-var-server; }
|
||||
.@{fa-css-prefix}-user-plus:before { content: @fa-var-user-plus; }
|
||||
.@{fa-css-prefix}-user-times:before { content: @fa-var-user-times; }
|
||||
.@{fa-css-prefix}-hotel:before,
|
||||
.@{fa-css-prefix}-bed:before { content: @fa-var-bed; }
|
||||
.@{fa-css-prefix}-viacoin:before { content: @fa-var-viacoin; }
|
||||
.@{fa-css-prefix}-train:before { content: @fa-var-train; }
|
||||
.@{fa-css-prefix}-subway:before { content: @fa-var-subway; }
|
||||
.@{fa-css-prefix}-medium:before { content: @fa-var-medium; }
|
||||
.@{fa-css-prefix}-yc:before,
|
||||
.@{fa-css-prefix}-y-combinator:before { content: @fa-var-y-combinator; }
|
||||
.@{fa-css-prefix}-optin-monster:before { content: @fa-var-optin-monster; }
|
||||
.@{fa-css-prefix}-opencart:before { content: @fa-var-opencart; }
|
||||
.@{fa-css-prefix}-expeditedssl:before { content: @fa-var-expeditedssl; }
|
||||
.@{fa-css-prefix}-battery-4:before,
|
||||
.@{fa-css-prefix}-battery:before,
|
||||
.@{fa-css-prefix}-battery-full:before { content: @fa-var-battery-full; }
|
||||
.@{fa-css-prefix}-battery-3:before,
|
||||
.@{fa-css-prefix}-battery-three-quarters:before { content: @fa-var-battery-three-quarters; }
|
||||
.@{fa-css-prefix}-battery-2:before,
|
||||
.@{fa-css-prefix}-battery-half:before { content: @fa-var-battery-half; }
|
||||
.@{fa-css-prefix}-battery-1:before,
|
||||
.@{fa-css-prefix}-battery-quarter:before { content: @fa-var-battery-quarter; }
|
||||
.@{fa-css-prefix}-battery-0:before,
|
||||
.@{fa-css-prefix}-battery-empty:before { content: @fa-var-battery-empty; }
|
||||
.@{fa-css-prefix}-mouse-pointer:before { content: @fa-var-mouse-pointer; }
|
||||
.@{fa-css-prefix}-i-cursor:before { content: @fa-var-i-cursor; }
|
||||
.@{fa-css-prefix}-object-group:before { content: @fa-var-object-group; }
|
||||
.@{fa-css-prefix}-object-ungroup:before { content: @fa-var-object-ungroup; }
|
||||
.@{fa-css-prefix}-sticky-note:before { content: @fa-var-sticky-note; }
|
||||
.@{fa-css-prefix}-sticky-note-o:before { content: @fa-var-sticky-note-o; }
|
||||
.@{fa-css-prefix}-cc-jcb:before { content: @fa-var-cc-jcb; }
|
||||
.@{fa-css-prefix}-cc-diners-club:before { content: @fa-var-cc-diners-club; }
|
||||
.@{fa-css-prefix}-clone:before { content: @fa-var-clone; }
|
||||
.@{fa-css-prefix}-balance-scale:before { content: @fa-var-balance-scale; }
|
||||
.@{fa-css-prefix}-hourglass-o:before { content: @fa-var-hourglass-o; }
|
||||
.@{fa-css-prefix}-hourglass-1:before,
|
||||
.@{fa-css-prefix}-hourglass-start:before { content: @fa-var-hourglass-start; }
|
||||
.@{fa-css-prefix}-hourglass-2:before,
|
||||
.@{fa-css-prefix}-hourglass-half:before { content: @fa-var-hourglass-half; }
|
||||
.@{fa-css-prefix}-hourglass-3:before,
|
||||
.@{fa-css-prefix}-hourglass-end:before { content: @fa-var-hourglass-end; }
|
||||
.@{fa-css-prefix}-hourglass:before { content: @fa-var-hourglass; }
|
||||
.@{fa-css-prefix}-hand-grab-o:before,
|
||||
.@{fa-css-prefix}-hand-rock-o:before { content: @fa-var-hand-rock-o; }
|
||||
.@{fa-css-prefix}-hand-stop-o:before,
|
||||
.@{fa-css-prefix}-hand-paper-o:before { content: @fa-var-hand-paper-o; }
|
||||
.@{fa-css-prefix}-hand-scissors-o:before { content: @fa-var-hand-scissors-o; }
|
||||
.@{fa-css-prefix}-hand-lizard-o:before { content: @fa-var-hand-lizard-o; }
|
||||
.@{fa-css-prefix}-hand-spock-o:before { content: @fa-var-hand-spock-o; }
|
||||
.@{fa-css-prefix}-hand-pointer-o:before { content: @fa-var-hand-pointer-o; }
|
||||
.@{fa-css-prefix}-hand-peace-o:before { content: @fa-var-hand-peace-o; }
|
||||
.@{fa-css-prefix}-trademark:before { content: @fa-var-trademark; }
|
||||
.@{fa-css-prefix}-registered:before { content: @fa-var-registered; }
|
||||
.@{fa-css-prefix}-creative-commons:before { content: @fa-var-creative-commons; }
|
||||
.@{fa-css-prefix}-gg:before { content: @fa-var-gg; }
|
||||
.@{fa-css-prefix}-gg-circle:before { content: @fa-var-gg-circle; }
|
||||
.@{fa-css-prefix}-tripadvisor:before { content: @fa-var-tripadvisor; }
|
||||
.@{fa-css-prefix}-odnoklassniki:before { content: @fa-var-odnoklassniki; }
|
||||
.@{fa-css-prefix}-odnoklassniki-square:before { content: @fa-var-odnoklassniki-square; }
|
||||
.@{fa-css-prefix}-get-pocket:before { content: @fa-var-get-pocket; }
|
||||
.@{fa-css-prefix}-wikipedia-w:before { content: @fa-var-wikipedia-w; }
|
||||
.@{fa-css-prefix}-safari:before { content: @fa-var-safari; }
|
||||
.@{fa-css-prefix}-chrome:before { content: @fa-var-chrome; }
|
||||
.@{fa-css-prefix}-firefox:before { content: @fa-var-firefox; }
|
||||
.@{fa-css-prefix}-opera:before { content: @fa-var-opera; }
|
||||
.@{fa-css-prefix}-internet-explorer:before { content: @fa-var-internet-explorer; }
|
||||
.@{fa-css-prefix}-tv:before,
|
||||
.@{fa-css-prefix}-television:before { content: @fa-var-television; }
|
||||
.@{fa-css-prefix}-contao:before { content: @fa-var-contao; }
|
||||
.@{fa-css-prefix}-500px:before { content: @fa-var-500px; }
|
||||
.@{fa-css-prefix}-amazon:before { content: @fa-var-amazon; }
|
||||
.@{fa-css-prefix}-calendar-plus-o:before { content: @fa-var-calendar-plus-o; }
|
||||
.@{fa-css-prefix}-calendar-minus-o:before { content: @fa-var-calendar-minus-o; }
|
||||
.@{fa-css-prefix}-calendar-times-o:before { content: @fa-var-calendar-times-o; }
|
||||
.@{fa-css-prefix}-calendar-check-o:before { content: @fa-var-calendar-check-o; }
|
||||
.@{fa-css-prefix}-industry:before { content: @fa-var-industry; }
|
||||
.@{fa-css-prefix}-map-pin:before { content: @fa-var-map-pin; }
|
||||
.@{fa-css-prefix}-map-signs:before { content: @fa-var-map-signs; }
|
||||
.@{fa-css-prefix}-map-o:before { content: @fa-var-map-o; }
|
||||
.@{fa-css-prefix}-map:before { content: @fa-var-map; }
|
||||
.@{fa-css-prefix}-commenting:before { content: @fa-var-commenting; }
|
||||
.@{fa-css-prefix}-commenting-o:before { content: @fa-var-commenting-o; }
|
||||
.@{fa-css-prefix}-houzz:before { content: @fa-var-houzz; }
|
||||
.@{fa-css-prefix}-vimeo:before { content: @fa-var-vimeo; }
|
||||
.@{fa-css-prefix}-black-tie:before { content: @fa-var-black-tie; }
|
||||
.@{fa-css-prefix}-fonticons:before { content: @fa-var-fonticons; }
|
||||
.@{fa-css-prefix}-reddit-alien:before { content: @fa-var-reddit-alien; }
|
||||
.@{fa-css-prefix}-edge:before { content: @fa-var-edge; }
|
||||
.@{fa-css-prefix}-credit-card-alt:before { content: @fa-var-credit-card-alt; }
|
||||
.@{fa-css-prefix}-codiepie:before { content: @fa-var-codiepie; }
|
||||
.@{fa-css-prefix}-modx:before { content: @fa-var-modx; }
|
||||
.@{fa-css-prefix}-fort-awesome:before { content: @fa-var-fort-awesome; }
|
||||
.@{fa-css-prefix}-usb:before { content: @fa-var-usb; }
|
||||
.@{fa-css-prefix}-product-hunt:before { content: @fa-var-product-hunt; }
|
||||
.@{fa-css-prefix}-mixcloud:before { content: @fa-var-mixcloud; }
|
||||
.@{fa-css-prefix}-scribd:before { content: @fa-var-scribd; }
|
||||
.@{fa-css-prefix}-pause-circle:before { content: @fa-var-pause-circle; }
|
||||
.@{fa-css-prefix}-pause-circle-o:before { content: @fa-var-pause-circle-o; }
|
||||
.@{fa-css-prefix}-stop-circle:before { content: @fa-var-stop-circle; }
|
||||
.@{fa-css-prefix}-stop-circle-o:before { content: @fa-var-stop-circle-o; }
|
||||
.@{fa-css-prefix}-shopping-bag:before { content: @fa-var-shopping-bag; }
|
||||
.@{fa-css-prefix}-shopping-basket:before { content: @fa-var-shopping-basket; }
|
||||
.@{fa-css-prefix}-hashtag:before { content: @fa-var-hashtag; }
|
||||
.@{fa-css-prefix}-bluetooth:before { content: @fa-var-bluetooth; }
|
||||
.@{fa-css-prefix}-bluetooth-b:before { content: @fa-var-bluetooth-b; }
|
||||
.@{fa-css-prefix}-percent:before { content: @fa-var-percent; }
|
||||
.@{fa-css-prefix}-gitlab:before { content: @fa-var-gitlab; }
|
||||
.@{fa-css-prefix}-wpbeginner:before { content: @fa-var-wpbeginner; }
|
||||
.@{fa-css-prefix}-wpforms:before { content: @fa-var-wpforms; }
|
||||
.@{fa-css-prefix}-envira:before { content: @fa-var-envira; }
|
||||
.@{fa-css-prefix}-universal-access:before { content: @fa-var-universal-access; }
|
||||
.@{fa-css-prefix}-wheelchair-alt:before { content: @fa-var-wheelchair-alt; }
|
||||
.@{fa-css-prefix}-question-circle-o:before { content: @fa-var-question-circle-o; }
|
||||
.@{fa-css-prefix}-blind:before { content: @fa-var-blind; }
|
||||
.@{fa-css-prefix}-audio-description:before { content: @fa-var-audio-description; }
|
||||
.@{fa-css-prefix}-volume-control-phone:before { content: @fa-var-volume-control-phone; }
|
||||
.@{fa-css-prefix}-braille:before { content: @fa-var-braille; }
|
||||
.@{fa-css-prefix}-assistive-listening-systems:before { content: @fa-var-assistive-listening-systems; }
|
||||
.@{fa-css-prefix}-asl-interpreting:before,
|
||||
.@{fa-css-prefix}-american-sign-language-interpreting:before { content: @fa-var-american-sign-language-interpreting; }
|
||||
.@{fa-css-prefix}-deafness:before,
|
||||
.@{fa-css-prefix}-hard-of-hearing:before,
|
||||
.@{fa-css-prefix}-deaf:before { content: @fa-var-deaf; }
|
||||
.@{fa-css-prefix}-glide:before { content: @fa-var-glide; }
|
||||
.@{fa-css-prefix}-glide-g:before { content: @fa-var-glide-g; }
|
||||
.@{fa-css-prefix}-signing:before,
|
||||
.@{fa-css-prefix}-sign-language:before { content: @fa-var-sign-language; }
|
||||
.@{fa-css-prefix}-low-vision:before { content: @fa-var-low-vision; }
|
||||
.@{fa-css-prefix}-viadeo:before { content: @fa-var-viadeo; }
|
||||
.@{fa-css-prefix}-viadeo-square:before { content: @fa-var-viadeo-square; }
|
||||
.@{fa-css-prefix}-snapchat:before { content: @fa-var-snapchat; }
|
||||
.@{fa-css-prefix}-snapchat-ghost:before { content: @fa-var-snapchat-ghost; }
|
||||
.@{fa-css-prefix}-snapchat-square:before { content: @fa-var-snapchat-square; }
|
||||
.@{fa-css-prefix}-pied-piper:before { content: @fa-var-pied-piper; }
|
||||
.@{fa-css-prefix}-first-order:before { content: @fa-var-first-order; }
|
||||
.@{fa-css-prefix}-yoast:before { content: @fa-var-yoast; }
|
||||
.@{fa-css-prefix}-themeisle:before { content: @fa-var-themeisle; }
|
||||
.@{fa-css-prefix}-google-plus-circle:before,
|
||||
.@{fa-css-prefix}-google-plus-official:before { content: @fa-var-google-plus-official; }
|
||||
.@{fa-css-prefix}-fa:before,
|
||||
.@{fa-css-prefix}-font-awesome:before { content: @fa-var-font-awesome; }
|
||||
.@{fa-css-prefix}-handshake-o:before { content: @fa-var-handshake-o; }
|
||||
.@{fa-css-prefix}-envelope-open:before { content: @fa-var-envelope-open; }
|
||||
.@{fa-css-prefix}-envelope-open-o:before { content: @fa-var-envelope-open-o; }
|
||||
.@{fa-css-prefix}-linode:before { content: @fa-var-linode; }
|
||||
.@{fa-css-prefix}-address-book:before { content: @fa-var-address-book; }
|
||||
.@{fa-css-prefix}-address-book-o:before { content: @fa-var-address-book-o; }
|
||||
.@{fa-css-prefix}-vcard:before,
|
||||
.@{fa-css-prefix}-address-card:before { content: @fa-var-address-card; }
|
||||
.@{fa-css-prefix}-vcard-o:before,
|
||||
.@{fa-css-prefix}-address-card-o:before { content: @fa-var-address-card-o; }
|
||||
.@{fa-css-prefix}-user-circle:before { content: @fa-var-user-circle; }
|
||||
.@{fa-css-prefix}-user-circle-o:before { content: @fa-var-user-circle-o; }
|
||||
.@{fa-css-prefix}-user-o:before { content: @fa-var-user-o; }
|
||||
.@{fa-css-prefix}-id-badge:before { content: @fa-var-id-badge; }
|
||||
.@{fa-css-prefix}-drivers-license:before,
|
||||
.@{fa-css-prefix}-id-card:before { content: @fa-var-id-card; }
|
||||
.@{fa-css-prefix}-drivers-license-o:before,
|
||||
.@{fa-css-prefix}-id-card-o:before { content: @fa-var-id-card-o; }
|
||||
.@{fa-css-prefix}-quora:before { content: @fa-var-quora; }
|
||||
.@{fa-css-prefix}-free-code-camp:before { content: @fa-var-free-code-camp; }
|
||||
.@{fa-css-prefix}-telegram:before { content: @fa-var-telegram; }
|
||||
.@{fa-css-prefix}-thermometer-4:before,
|
||||
.@{fa-css-prefix}-thermometer:before,
|
||||
.@{fa-css-prefix}-thermometer-full:before { content: @fa-var-thermometer-full; }
|
||||
.@{fa-css-prefix}-thermometer-3:before,
|
||||
.@{fa-css-prefix}-thermometer-three-quarters:before { content: @fa-var-thermometer-three-quarters; }
|
||||
.@{fa-css-prefix}-thermometer-2:before,
|
||||
.@{fa-css-prefix}-thermometer-half:before { content: @fa-var-thermometer-half; }
|
||||
.@{fa-css-prefix}-thermometer-1:before,
|
||||
.@{fa-css-prefix}-thermometer-quarter:before { content: @fa-var-thermometer-quarter; }
|
||||
.@{fa-css-prefix}-thermometer-0:before,
|
||||
.@{fa-css-prefix}-thermometer-empty:before { content: @fa-var-thermometer-empty; }
|
||||
.@{fa-css-prefix}-shower:before { content: @fa-var-shower; }
|
||||
.@{fa-css-prefix}-bathtub:before,
|
||||
.@{fa-css-prefix}-s15:before,
|
||||
.@{fa-css-prefix}-bath:before { content: @fa-var-bath; }
|
||||
.@{fa-css-prefix}-podcast:before { content: @fa-var-podcast; }
|
||||
.@{fa-css-prefix}-window-maximize:before { content: @fa-var-window-maximize; }
|
||||
.@{fa-css-prefix}-window-minimize:before { content: @fa-var-window-minimize; }
|
||||
.@{fa-css-prefix}-window-restore:before { content: @fa-var-window-restore; }
|
||||
.@{fa-css-prefix}-times-rectangle:before,
|
||||
.@{fa-css-prefix}-window-close:before { content: @fa-var-window-close; }
|
||||
.@{fa-css-prefix}-times-rectangle-o:before,
|
||||
.@{fa-css-prefix}-window-close-o:before { content: @fa-var-window-close-o; }
|
||||
.@{fa-css-prefix}-bandcamp:before { content: @fa-var-bandcamp; }
|
||||
.@{fa-css-prefix}-grav:before { content: @fa-var-grav; }
|
||||
.@{fa-css-prefix}-etsy:before { content: @fa-var-etsy; }
|
||||
.@{fa-css-prefix}-imdb:before { content: @fa-var-imdb; }
|
||||
.@{fa-css-prefix}-ravelry:before { content: @fa-var-ravelry; }
|
||||
.@{fa-css-prefix}-eercast:before { content: @fa-var-eercast; }
|
||||
.@{fa-css-prefix}-microchip:before { content: @fa-var-microchip; }
|
||||
.@{fa-css-prefix}-snowflake-o:before { content: @fa-var-snowflake-o; }
|
||||
.@{fa-css-prefix}-superpowers:before { content: @fa-var-superpowers; }
|
||||
.@{fa-css-prefix}-wpexplorer:before { content: @fa-var-wpexplorer; }
|
||||
.@{fa-css-prefix}-meetup:before { content: @fa-var-meetup; }
|
||||
|
|
|
|||
|
|
@ -3,23 +3,58 @@
|
|||
|
||||
.fa-icon() {
|
||||
display: inline-block;
|
||||
font: normal normal normal 14px/1 FontAwesome; // shortening font declaration
|
||||
font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
|
||||
font-size: inherit; // can't have font-size inherit on line above, so need to override
|
||||
text-rendering: auto; // optimizelegibility throws things off #1094
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
}
|
||||
|
||||
.fa-icon-rotate(@degrees, @rotation) {
|
||||
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation);
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})";
|
||||
-webkit-transform: rotate(@degrees);
|
||||
-ms-transform: rotate(@degrees);
|
||||
transform: rotate(@degrees);
|
||||
}
|
||||
|
||||
.fa-icon-flip(@horiz, @vert, @rotation) {
|
||||
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation, mirror=1);
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)";
|
||||
-webkit-transform: scale(@horiz, @vert);
|
||||
-ms-transform: scale(@horiz, @vert);
|
||||
transform: scale(@horiz, @vert);
|
||||
}
|
||||
|
||||
|
||||
// Only display content to screen readers. A la Bootstrap 4.
|
||||
//
|
||||
// See: http://a11yproject.com/posts/how-to-hide-content/
|
||||
|
||||
.sr-only() {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0,0,0,0);
|
||||
border: 0;
|
||||
}
|
||||
|
||||
// Use in conjunction with .sr-only to only display content when it's focused.
|
||||
//
|
||||
// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
|
||||
//
|
||||
// Credit: HTML5 Boilerplate
|
||||
|
||||
.sr-only-focusable() {
|
||||
&:active,
|
||||
&:focus {
|
||||
position: static;
|
||||
width: auto;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
overflow: visible;
|
||||
clip: auto;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@
|
|||
font-family: 'FontAwesome';
|
||||
src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}');
|
||||
src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'),
|
||||
url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'),
|
||||
url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'),
|
||||
url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'),
|
||||
url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg');
|
||||
// src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
|
||||
// src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
|
|
|||
5
assets/font/fonts-awesome/less/screen-reader.less
Normal file
5
assets/font/fonts-awesome/less/screen-reader.less
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// Screen Readers
|
||||
// -------------------------
|
||||
|
||||
.sr-only { .sr-only(); }
|
||||
.sr-only-focusable { .sr-only-focusable(); }
|
||||
|
|
@ -2,20 +2,29 @@
|
|||
// --------------------------
|
||||
|
||||
@fa-font-path: "../fonts";
|
||||
//@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.2.0/fonts"; // for referencing Bootstrap CDN font files directly
|
||||
@fa-font-size-base: 14px;
|
||||
@fa-line-height-base: 1;
|
||||
//@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.7.0/fonts"; // for referencing Bootstrap CDN font files directly
|
||||
@fa-css-prefix: fa;
|
||||
@fa-version: "4.2.0";
|
||||
@fa-version: "4.7.0";
|
||||
@fa-border-color: #eee;
|
||||
@fa-inverse: #fff;
|
||||
@fa-li-width: (30em / 14);
|
||||
|
||||
@fa-var-500px: "\f26e";
|
||||
@fa-var-address-book: "\f2b9";
|
||||
@fa-var-address-book-o: "\f2ba";
|
||||
@fa-var-address-card: "\f2bb";
|
||||
@fa-var-address-card-o: "\f2bc";
|
||||
@fa-var-adjust: "\f042";
|
||||
@fa-var-adn: "\f170";
|
||||
@fa-var-align-center: "\f037";
|
||||
@fa-var-align-justify: "\f039";
|
||||
@fa-var-align-left: "\f036";
|
||||
@fa-var-align-right: "\f038";
|
||||
@fa-var-amazon: "\f270";
|
||||
@fa-var-ambulance: "\f0f9";
|
||||
@fa-var-american-sign-language-interpreting: "\f2a3";
|
||||
@fa-var-anchor: "\f13d";
|
||||
@fa-var-android: "\f17b";
|
||||
@fa-var-angellist: "\f209";
|
||||
|
|
@ -46,16 +55,35 @@
|
|||
@fa-var-arrows-alt: "\f0b2";
|
||||
@fa-var-arrows-h: "\f07e";
|
||||
@fa-var-arrows-v: "\f07d";
|
||||
@fa-var-asl-interpreting: "\f2a3";
|
||||
@fa-var-assistive-listening-systems: "\f2a2";
|
||||
@fa-var-asterisk: "\f069";
|
||||
@fa-var-at: "\f1fa";
|
||||
@fa-var-audio-description: "\f29e";
|
||||
@fa-var-automobile: "\f1b9";
|
||||
@fa-var-backward: "\f04a";
|
||||
@fa-var-balance-scale: "\f24e";
|
||||
@fa-var-ban: "\f05e";
|
||||
@fa-var-bandcamp: "\f2d5";
|
||||
@fa-var-bank: "\f19c";
|
||||
@fa-var-bar-chart: "\f080";
|
||||
@fa-var-bar-chart-o: "\f080";
|
||||
@fa-var-barcode: "\f02a";
|
||||
@fa-var-bars: "\f0c9";
|
||||
@fa-var-bath: "\f2cd";
|
||||
@fa-var-bathtub: "\f2cd";
|
||||
@fa-var-battery: "\f240";
|
||||
@fa-var-battery-0: "\f244";
|
||||
@fa-var-battery-1: "\f243";
|
||||
@fa-var-battery-2: "\f242";
|
||||
@fa-var-battery-3: "\f241";
|
||||
@fa-var-battery-4: "\f240";
|
||||
@fa-var-battery-empty: "\f244";
|
||||
@fa-var-battery-full: "\f240";
|
||||
@fa-var-battery-half: "\f242";
|
||||
@fa-var-battery-quarter: "\f243";
|
||||
@fa-var-battery-three-quarters: "\f241";
|
||||
@fa-var-bed: "\f236";
|
||||
@fa-var-beer: "\f0fc";
|
||||
@fa-var-behance: "\f1b4";
|
||||
@fa-var-behance-square: "\f1b5";
|
||||
|
|
@ -69,12 +97,17 @@
|
|||
@fa-var-bitbucket: "\f171";
|
||||
@fa-var-bitbucket-square: "\f172";
|
||||
@fa-var-bitcoin: "\f15a";
|
||||
@fa-var-black-tie: "\f27e";
|
||||
@fa-var-blind: "\f29d";
|
||||
@fa-var-bluetooth: "\f293";
|
||||
@fa-var-bluetooth-b: "\f294";
|
||||
@fa-var-bold: "\f032";
|
||||
@fa-var-bolt: "\f0e7";
|
||||
@fa-var-bomb: "\f1e2";
|
||||
@fa-var-book: "\f02d";
|
||||
@fa-var-bookmark: "\f02e";
|
||||
@fa-var-bookmark-o: "\f097";
|
||||
@fa-var-braille: "\f2a1";
|
||||
@fa-var-briefcase: "\f0b1";
|
||||
@fa-var-btc: "\f15a";
|
||||
@fa-var-bug: "\f188";
|
||||
|
|
@ -83,10 +116,15 @@
|
|||
@fa-var-bullhorn: "\f0a1";
|
||||
@fa-var-bullseye: "\f140";
|
||||
@fa-var-bus: "\f207";
|
||||
@fa-var-buysellads: "\f20d";
|
||||
@fa-var-cab: "\f1ba";
|
||||
@fa-var-calculator: "\f1ec";
|
||||
@fa-var-calendar: "\f073";
|
||||
@fa-var-calendar-check-o: "\f274";
|
||||
@fa-var-calendar-minus-o: "\f272";
|
||||
@fa-var-calendar-o: "\f133";
|
||||
@fa-var-calendar-plus-o: "\f271";
|
||||
@fa-var-calendar-times-o: "\f273";
|
||||
@fa-var-camera: "\f030";
|
||||
@fa-var-camera-retro: "\f083";
|
||||
@fa-var-car: "\f1b9";
|
||||
|
|
@ -98,9 +136,13 @@
|
|||
@fa-var-caret-square-o-right: "\f152";
|
||||
@fa-var-caret-square-o-up: "\f151";
|
||||
@fa-var-caret-up: "\f0d8";
|
||||
@fa-var-cart-arrow-down: "\f218";
|
||||
@fa-var-cart-plus: "\f217";
|
||||
@fa-var-cc: "\f20a";
|
||||
@fa-var-cc-amex: "\f1f3";
|
||||
@fa-var-cc-diners-club: "\f24c";
|
||||
@fa-var-cc-discover: "\f1f2";
|
||||
@fa-var-cc-jcb: "\f24b";
|
||||
@fa-var-cc-mastercard: "\f1f1";
|
||||
@fa-var-cc-paypal: "\f1f4";
|
||||
@fa-var-cc-stripe: "\f1f5";
|
||||
|
|
@ -122,12 +164,14 @@
|
|||
@fa-var-chevron-right: "\f054";
|
||||
@fa-var-chevron-up: "\f077";
|
||||
@fa-var-child: "\f1ae";
|
||||
@fa-var-chrome: "\f268";
|
||||
@fa-var-circle: "\f111";
|
||||
@fa-var-circle-o: "\f10c";
|
||||
@fa-var-circle-o-notch: "\f1ce";
|
||||
@fa-var-circle-thin: "\f1db";
|
||||
@fa-var-clipboard: "\f0ea";
|
||||
@fa-var-clock-o: "\f017";
|
||||
@fa-var-clone: "\f24d";
|
||||
@fa-var-close: "\f00d";
|
||||
@fa-var-cloud: "\f0c2";
|
||||
@fa-var-cloud-download: "\f0ed";
|
||||
|
|
@ -136,19 +180,26 @@
|
|||
@fa-var-code: "\f121";
|
||||
@fa-var-code-fork: "\f126";
|
||||
@fa-var-codepen: "\f1cb";
|
||||
@fa-var-codiepie: "\f284";
|
||||
@fa-var-coffee: "\f0f4";
|
||||
@fa-var-cog: "\f013";
|
||||
@fa-var-cogs: "\f085";
|
||||
@fa-var-columns: "\f0db";
|
||||
@fa-var-comment: "\f075";
|
||||
@fa-var-comment-o: "\f0e5";
|
||||
@fa-var-commenting: "\f27a";
|
||||
@fa-var-commenting-o: "\f27b";
|
||||
@fa-var-comments: "\f086";
|
||||
@fa-var-comments-o: "\f0e6";
|
||||
@fa-var-compass: "\f14e";
|
||||
@fa-var-compress: "\f066";
|
||||
@fa-var-connectdevelop: "\f20e";
|
||||
@fa-var-contao: "\f26d";
|
||||
@fa-var-copy: "\f0c5";
|
||||
@fa-var-copyright: "\f1f9";
|
||||
@fa-var-creative-commons: "\f25e";
|
||||
@fa-var-credit-card: "\f09d";
|
||||
@fa-var-credit-card-alt: "\f283";
|
||||
@fa-var-crop: "\f125";
|
||||
@fa-var-crosshairs: "\f05b";
|
||||
@fa-var-css3: "\f13c";
|
||||
|
|
@ -157,27 +208,39 @@
|
|||
@fa-var-cut: "\f0c4";
|
||||
@fa-var-cutlery: "\f0f5";
|
||||
@fa-var-dashboard: "\f0e4";
|
||||
@fa-var-dashcube: "\f210";
|
||||
@fa-var-database: "\f1c0";
|
||||
@fa-var-deaf: "\f2a4";
|
||||
@fa-var-deafness: "\f2a4";
|
||||
@fa-var-dedent: "\f03b";
|
||||
@fa-var-delicious: "\f1a5";
|
||||
@fa-var-desktop: "\f108";
|
||||
@fa-var-deviantart: "\f1bd";
|
||||
@fa-var-diamond: "\f219";
|
||||
@fa-var-digg: "\f1a6";
|
||||
@fa-var-dollar: "\f155";
|
||||
@fa-var-dot-circle-o: "\f192";
|
||||
@fa-var-download: "\f019";
|
||||
@fa-var-dribbble: "\f17d";
|
||||
@fa-var-drivers-license: "\f2c2";
|
||||
@fa-var-drivers-license-o: "\f2c3";
|
||||
@fa-var-dropbox: "\f16b";
|
||||
@fa-var-drupal: "\f1a9";
|
||||
@fa-var-edge: "\f282";
|
||||
@fa-var-edit: "\f044";
|
||||
@fa-var-eercast: "\f2da";
|
||||
@fa-var-eject: "\f052";
|
||||
@fa-var-ellipsis-h: "\f141";
|
||||
@fa-var-ellipsis-v: "\f142";
|
||||
@fa-var-empire: "\f1d1";
|
||||
@fa-var-envelope: "\f0e0";
|
||||
@fa-var-envelope-o: "\f003";
|
||||
@fa-var-envelope-open: "\f2b6";
|
||||
@fa-var-envelope-open-o: "\f2b7";
|
||||
@fa-var-envelope-square: "\f199";
|
||||
@fa-var-envira: "\f299";
|
||||
@fa-var-eraser: "\f12d";
|
||||
@fa-var-etsy: "\f2d7";
|
||||
@fa-var-eur: "\f153";
|
||||
@fa-var-euro: "\f153";
|
||||
@fa-var-exchange: "\f0ec";
|
||||
|
|
@ -185,16 +248,21 @@
|
|||
@fa-var-exclamation-circle: "\f06a";
|
||||
@fa-var-exclamation-triangle: "\f071";
|
||||
@fa-var-expand: "\f065";
|
||||
@fa-var-expeditedssl: "\f23e";
|
||||
@fa-var-external-link: "\f08e";
|
||||
@fa-var-external-link-square: "\f14c";
|
||||
@fa-var-eye: "\f06e";
|
||||
@fa-var-eye-slash: "\f070";
|
||||
@fa-var-eyedropper: "\f1fb";
|
||||
@fa-var-fa: "\f2b4";
|
||||
@fa-var-facebook: "\f09a";
|
||||
@fa-var-facebook-f: "\f09a";
|
||||
@fa-var-facebook-official: "\f230";
|
||||
@fa-var-facebook-square: "\f082";
|
||||
@fa-var-fast-backward: "\f049";
|
||||
@fa-var-fast-forward: "\f050";
|
||||
@fa-var-fax: "\f1ac";
|
||||
@fa-var-feed: "\f09e";
|
||||
@fa-var-female: "\f182";
|
||||
@fa-var-fighter-jet: "\f0fb";
|
||||
@fa-var-file: "\f15b";
|
||||
|
|
@ -220,6 +288,8 @@
|
|||
@fa-var-filter: "\f0b0";
|
||||
@fa-var-fire: "\f06d";
|
||||
@fa-var-fire-extinguisher: "\f134";
|
||||
@fa-var-firefox: "\f269";
|
||||
@fa-var-first-order: "\f2b0";
|
||||
@fa-var-flag: "\f024";
|
||||
@fa-var-flag-checkered: "\f11e";
|
||||
@fa-var-flag-o: "\f11d";
|
||||
|
|
@ -232,8 +302,13 @@
|
|||
@fa-var-folder-open: "\f07c";
|
||||
@fa-var-folder-open-o: "\f115";
|
||||
@fa-var-font: "\f031";
|
||||
@fa-var-font-awesome: "\f2b4";
|
||||
@fa-var-fonticons: "\f280";
|
||||
@fa-var-fort-awesome: "\f286";
|
||||
@fa-var-forumbee: "\f211";
|
||||
@fa-var-forward: "\f04e";
|
||||
@fa-var-foursquare: "\f180";
|
||||
@fa-var-free-code-camp: "\f2c5";
|
||||
@fa-var-frown-o: "\f119";
|
||||
@fa-var-futbol-o: "\f1e3";
|
||||
@fa-var-gamepad: "\f11b";
|
||||
|
|
@ -242,45 +317,87 @@
|
|||
@fa-var-ge: "\f1d1";
|
||||
@fa-var-gear: "\f013";
|
||||
@fa-var-gears: "\f085";
|
||||
@fa-var-genderless: "\f22d";
|
||||
@fa-var-get-pocket: "\f265";
|
||||
@fa-var-gg: "\f260";
|
||||
@fa-var-gg-circle: "\f261";
|
||||
@fa-var-gift: "\f06b";
|
||||
@fa-var-git: "\f1d3";
|
||||
@fa-var-git-square: "\f1d2";
|
||||
@fa-var-github: "\f09b";
|
||||
@fa-var-github-alt: "\f113";
|
||||
@fa-var-github-square: "\f092";
|
||||
@fa-var-gitlab: "\f296";
|
||||
@fa-var-gittip: "\f184";
|
||||
@fa-var-glass: "\f000";
|
||||
@fa-var-glide: "\f2a5";
|
||||
@fa-var-glide-g: "\f2a6";
|
||||
@fa-var-globe: "\f0ac";
|
||||
@fa-var-google: "\f1a0";
|
||||
@fa-var-google-plus: "\f0d5";
|
||||
@fa-var-google-plus-circle: "\f2b3";
|
||||
@fa-var-google-plus-official: "\f2b3";
|
||||
@fa-var-google-plus-square: "\f0d4";
|
||||
@fa-var-google-wallet: "\f1ee";
|
||||
@fa-var-graduation-cap: "\f19d";
|
||||
@fa-var-gratipay: "\f184";
|
||||
@fa-var-grav: "\f2d6";
|
||||
@fa-var-group: "\f0c0";
|
||||
@fa-var-h-square: "\f0fd";
|
||||
@fa-var-hacker-news: "\f1d4";
|
||||
@fa-var-hand-grab-o: "\f255";
|
||||
@fa-var-hand-lizard-o: "\f258";
|
||||
@fa-var-hand-o-down: "\f0a7";
|
||||
@fa-var-hand-o-left: "\f0a5";
|
||||
@fa-var-hand-o-right: "\f0a4";
|
||||
@fa-var-hand-o-up: "\f0a6";
|
||||
@fa-var-hand-paper-o: "\f256";
|
||||
@fa-var-hand-peace-o: "\f25b";
|
||||
@fa-var-hand-pointer-o: "\f25a";
|
||||
@fa-var-hand-rock-o: "\f255";
|
||||
@fa-var-hand-scissors-o: "\f257";
|
||||
@fa-var-hand-spock-o: "\f259";
|
||||
@fa-var-hand-stop-o: "\f256";
|
||||
@fa-var-handshake-o: "\f2b5";
|
||||
@fa-var-hard-of-hearing: "\f2a4";
|
||||
@fa-var-hashtag: "\f292";
|
||||
@fa-var-hdd-o: "\f0a0";
|
||||
@fa-var-header: "\f1dc";
|
||||
@fa-var-headphones: "\f025";
|
||||
@fa-var-heart: "\f004";
|
||||
@fa-var-heart-o: "\f08a";
|
||||
@fa-var-heartbeat: "\f21e";
|
||||
@fa-var-history: "\f1da";
|
||||
@fa-var-home: "\f015";
|
||||
@fa-var-hospital-o: "\f0f8";
|
||||
@fa-var-hotel: "\f236";
|
||||
@fa-var-hourglass: "\f254";
|
||||
@fa-var-hourglass-1: "\f251";
|
||||
@fa-var-hourglass-2: "\f252";
|
||||
@fa-var-hourglass-3: "\f253";
|
||||
@fa-var-hourglass-end: "\f253";
|
||||
@fa-var-hourglass-half: "\f252";
|
||||
@fa-var-hourglass-o: "\f250";
|
||||
@fa-var-hourglass-start: "\f251";
|
||||
@fa-var-houzz: "\f27c";
|
||||
@fa-var-html5: "\f13b";
|
||||
@fa-var-i-cursor: "\f246";
|
||||
@fa-var-id-badge: "\f2c1";
|
||||
@fa-var-id-card: "\f2c2";
|
||||
@fa-var-id-card-o: "\f2c3";
|
||||
@fa-var-ils: "\f20b";
|
||||
@fa-var-image: "\f03e";
|
||||
@fa-var-imdb: "\f2d8";
|
||||
@fa-var-inbox: "\f01c";
|
||||
@fa-var-indent: "\f03c";
|
||||
@fa-var-industry: "\f275";
|
||||
@fa-var-info: "\f129";
|
||||
@fa-var-info-circle: "\f05a";
|
||||
@fa-var-inr: "\f156";
|
||||
@fa-var-instagram: "\f16d";
|
||||
@fa-var-institution: "\f19c";
|
||||
@fa-var-internet-explorer: "\f26b";
|
||||
@fa-var-intersex: "\f224";
|
||||
@fa-var-ioxhost: "\f208";
|
||||
@fa-var-italic: "\f033";
|
||||
@fa-var-joomla: "\f1aa";
|
||||
|
|
@ -294,6 +411,7 @@
|
|||
@fa-var-lastfm: "\f202";
|
||||
@fa-var-lastfm-square: "\f203";
|
||||
@fa-var-leaf: "\f06c";
|
||||
@fa-var-leanpub: "\f212";
|
||||
@fa-var-legal: "\f0e3";
|
||||
@fa-var-lemon-o: "\f094";
|
||||
@fa-var-level-down: "\f149";
|
||||
|
|
@ -307,6 +425,7 @@
|
|||
@fa-var-link: "\f0c1";
|
||||
@fa-var-linkedin: "\f0e1";
|
||||
@fa-var-linkedin-square: "\f08c";
|
||||
@fa-var-linode: "\f2b8";
|
||||
@fa-var-linux: "\f17c";
|
||||
@fa-var-list: "\f03a";
|
||||
@fa-var-list-alt: "\f022";
|
||||
|
|
@ -318,32 +437,58 @@
|
|||
@fa-var-long-arrow-left: "\f177";
|
||||
@fa-var-long-arrow-right: "\f178";
|
||||
@fa-var-long-arrow-up: "\f176";
|
||||
@fa-var-low-vision: "\f2a8";
|
||||
@fa-var-magic: "\f0d0";
|
||||
@fa-var-magnet: "\f076";
|
||||
@fa-var-mail-forward: "\f064";
|
||||
@fa-var-mail-reply: "\f112";
|
||||
@fa-var-mail-reply-all: "\f122";
|
||||
@fa-var-male: "\f183";
|
||||
@fa-var-map: "\f279";
|
||||
@fa-var-map-marker: "\f041";
|
||||
@fa-var-map-o: "\f278";
|
||||
@fa-var-map-pin: "\f276";
|
||||
@fa-var-map-signs: "\f277";
|
||||
@fa-var-mars: "\f222";
|
||||
@fa-var-mars-double: "\f227";
|
||||
@fa-var-mars-stroke: "\f229";
|
||||
@fa-var-mars-stroke-h: "\f22b";
|
||||
@fa-var-mars-stroke-v: "\f22a";
|
||||
@fa-var-maxcdn: "\f136";
|
||||
@fa-var-meanpath: "\f20c";
|
||||
@fa-var-medium: "\f23a";
|
||||
@fa-var-medkit: "\f0fa";
|
||||
@fa-var-meetup: "\f2e0";
|
||||
@fa-var-meh-o: "\f11a";
|
||||
@fa-var-mercury: "\f223";
|
||||
@fa-var-microchip: "\f2db";
|
||||
@fa-var-microphone: "\f130";
|
||||
@fa-var-microphone-slash: "\f131";
|
||||
@fa-var-minus: "\f068";
|
||||
@fa-var-minus-circle: "\f056";
|
||||
@fa-var-minus-square: "\f146";
|
||||
@fa-var-minus-square-o: "\f147";
|
||||
@fa-var-mixcloud: "\f289";
|
||||
@fa-var-mobile: "\f10b";
|
||||
@fa-var-mobile-phone: "\f10b";
|
||||
@fa-var-modx: "\f285";
|
||||
@fa-var-money: "\f0d6";
|
||||
@fa-var-moon-o: "\f186";
|
||||
@fa-var-mortar-board: "\f19d";
|
||||
@fa-var-motorcycle: "\f21c";
|
||||
@fa-var-mouse-pointer: "\f245";
|
||||
@fa-var-music: "\f001";
|
||||
@fa-var-navicon: "\f0c9";
|
||||
@fa-var-neuter: "\f22c";
|
||||
@fa-var-newspaper-o: "\f1ea";
|
||||
@fa-var-object-group: "\f247";
|
||||
@fa-var-object-ungroup: "\f248";
|
||||
@fa-var-odnoklassniki: "\f263";
|
||||
@fa-var-odnoklassniki-square: "\f264";
|
||||
@fa-var-opencart: "\f23d";
|
||||
@fa-var-openid: "\f19b";
|
||||
@fa-var-opera: "\f26a";
|
||||
@fa-var-optin-monster: "\f23c";
|
||||
@fa-var-outdent: "\f03b";
|
||||
@fa-var-pagelines: "\f18c";
|
||||
@fa-var-paint-brush: "\f1fc";
|
||||
|
|
@ -353,19 +498,24 @@
|
|||
@fa-var-paragraph: "\f1dd";
|
||||
@fa-var-paste: "\f0ea";
|
||||
@fa-var-pause: "\f04c";
|
||||
@fa-var-pause-circle: "\f28b";
|
||||
@fa-var-pause-circle-o: "\f28c";
|
||||
@fa-var-paw: "\f1b0";
|
||||
@fa-var-paypal: "\f1ed";
|
||||
@fa-var-pencil: "\f040";
|
||||
@fa-var-pencil-square: "\f14b";
|
||||
@fa-var-pencil-square-o: "\f044";
|
||||
@fa-var-percent: "\f295";
|
||||
@fa-var-phone: "\f095";
|
||||
@fa-var-phone-square: "\f098";
|
||||
@fa-var-photo: "\f03e";
|
||||
@fa-var-picture-o: "\f03e";
|
||||
@fa-var-pie-chart: "\f200";
|
||||
@fa-var-pied-piper: "\f1a7";
|
||||
@fa-var-pied-piper: "\f2ae";
|
||||
@fa-var-pied-piper-alt: "\f1a8";
|
||||
@fa-var-pied-piper-pp: "\f1a7";
|
||||
@fa-var-pinterest: "\f0d2";
|
||||
@fa-var-pinterest-p: "\f231";
|
||||
@fa-var-pinterest-square: "\f0d3";
|
||||
@fa-var-plane: "\f072";
|
||||
@fa-var-play: "\f04b";
|
||||
|
|
@ -376,28 +526,36 @@
|
|||
@fa-var-plus-circle: "\f055";
|
||||
@fa-var-plus-square: "\f0fe";
|
||||
@fa-var-plus-square-o: "\f196";
|
||||
@fa-var-podcast: "\f2ce";
|
||||
@fa-var-power-off: "\f011";
|
||||
@fa-var-print: "\f02f";
|
||||
@fa-var-product-hunt: "\f288";
|
||||
@fa-var-puzzle-piece: "\f12e";
|
||||
@fa-var-qq: "\f1d6";
|
||||
@fa-var-qrcode: "\f029";
|
||||
@fa-var-question: "\f128";
|
||||
@fa-var-question-circle: "\f059";
|
||||
@fa-var-question-circle-o: "\f29c";
|
||||
@fa-var-quora: "\f2c4";
|
||||
@fa-var-quote-left: "\f10d";
|
||||
@fa-var-quote-right: "\f10e";
|
||||
@fa-var-ra: "\f1d0";
|
||||
@fa-var-random: "\f074";
|
||||
@fa-var-ravelry: "\f2d9";
|
||||
@fa-var-rebel: "\f1d0";
|
||||
@fa-var-recycle: "\f1b8";
|
||||
@fa-var-reddit: "\f1a1";
|
||||
@fa-var-reddit-alien: "\f281";
|
||||
@fa-var-reddit-square: "\f1a2";
|
||||
@fa-var-refresh: "\f021";
|
||||
@fa-var-registered: "\f25d";
|
||||
@fa-var-remove: "\f00d";
|
||||
@fa-var-renren: "\f18b";
|
||||
@fa-var-reorder: "\f0c9";
|
||||
@fa-var-repeat: "\f01e";
|
||||
@fa-var-reply: "\f112";
|
||||
@fa-var-reply-all: "\f122";
|
||||
@fa-var-resistance: "\f1d0";
|
||||
@fa-var-retweet: "\f079";
|
||||
@fa-var-rmb: "\f157";
|
||||
@fa-var-road: "\f018";
|
||||
|
|
@ -410,13 +568,18 @@
|
|||
@fa-var-rub: "\f158";
|
||||
@fa-var-ruble: "\f158";
|
||||
@fa-var-rupee: "\f156";
|
||||
@fa-var-s15: "\f2cd";
|
||||
@fa-var-safari: "\f267";
|
||||
@fa-var-save: "\f0c7";
|
||||
@fa-var-scissors: "\f0c4";
|
||||
@fa-var-scribd: "\f28a";
|
||||
@fa-var-search: "\f002";
|
||||
@fa-var-search-minus: "\f010";
|
||||
@fa-var-search-plus: "\f00e";
|
||||
@fa-var-sellsy: "\f213";
|
||||
@fa-var-send: "\f1d8";
|
||||
@fa-var-send-o: "\f1d9";
|
||||
@fa-var-server: "\f233";
|
||||
@fa-var-share: "\f064";
|
||||
@fa-var-share-alt: "\f1e0";
|
||||
@fa-var-share-alt-square: "\f1e1";
|
||||
|
|
@ -425,16 +588,29 @@
|
|||
@fa-var-shekel: "\f20b";
|
||||
@fa-var-sheqel: "\f20b";
|
||||
@fa-var-shield: "\f132";
|
||||
@fa-var-ship: "\f21a";
|
||||
@fa-var-shirtsinbulk: "\f214";
|
||||
@fa-var-shopping-bag: "\f290";
|
||||
@fa-var-shopping-basket: "\f291";
|
||||
@fa-var-shopping-cart: "\f07a";
|
||||
@fa-var-shower: "\f2cc";
|
||||
@fa-var-sign-in: "\f090";
|
||||
@fa-var-sign-language: "\f2a7";
|
||||
@fa-var-sign-out: "\f08b";
|
||||
@fa-var-signal: "\f012";
|
||||
@fa-var-signing: "\f2a7";
|
||||
@fa-var-simplybuilt: "\f215";
|
||||
@fa-var-sitemap: "\f0e8";
|
||||
@fa-var-skyatlas: "\f216";
|
||||
@fa-var-skype: "\f17e";
|
||||
@fa-var-slack: "\f198";
|
||||
@fa-var-sliders: "\f1de";
|
||||
@fa-var-slideshare: "\f1e7";
|
||||
@fa-var-smile-o: "\f118";
|
||||
@fa-var-snapchat: "\f2ab";
|
||||
@fa-var-snapchat-ghost: "\f2ac";
|
||||
@fa-var-snapchat-square: "\f2ad";
|
||||
@fa-var-snowflake-o: "\f2dc";
|
||||
@fa-var-soccer-ball-o: "\f1e3";
|
||||
@fa-var-sort: "\f0dc";
|
||||
@fa-var-sort-alpha-asc: "\f15d";
|
||||
|
|
@ -467,13 +643,20 @@
|
|||
@fa-var-step-backward: "\f048";
|
||||
@fa-var-step-forward: "\f051";
|
||||
@fa-var-stethoscope: "\f0f1";
|
||||
@fa-var-sticky-note: "\f249";
|
||||
@fa-var-sticky-note-o: "\f24a";
|
||||
@fa-var-stop: "\f04d";
|
||||
@fa-var-stop-circle: "\f28d";
|
||||
@fa-var-stop-circle-o: "\f28e";
|
||||
@fa-var-street-view: "\f21d";
|
||||
@fa-var-strikethrough: "\f0cc";
|
||||
@fa-var-stumbleupon: "\f1a4";
|
||||
@fa-var-stumbleupon-circle: "\f1a3";
|
||||
@fa-var-subscript: "\f12c";
|
||||
@fa-var-subway: "\f239";
|
||||
@fa-var-suitcase: "\f0f2";
|
||||
@fa-var-sun-o: "\f185";
|
||||
@fa-var-superpowers: "\f2dd";
|
||||
@fa-var-superscript: "\f12b";
|
||||
@fa-var-support: "\f1cd";
|
||||
@fa-var-table: "\f0ce";
|
||||
|
|
@ -483,6 +666,8 @@
|
|||
@fa-var-tags: "\f02c";
|
||||
@fa-var-tasks: "\f0ae";
|
||||
@fa-var-taxi: "\f1ba";
|
||||
@fa-var-telegram: "\f2c6";
|
||||
@fa-var-television: "\f26c";
|
||||
@fa-var-tencent-weibo: "\f1d5";
|
||||
@fa-var-terminal: "\f120";
|
||||
@fa-var-text-height: "\f034";
|
||||
|
|
@ -490,6 +675,18 @@
|
|||
@fa-var-th: "\f00a";
|
||||
@fa-var-th-large: "\f009";
|
||||
@fa-var-th-list: "\f00b";
|
||||
@fa-var-themeisle: "\f2b2";
|
||||
@fa-var-thermometer: "\f2c7";
|
||||
@fa-var-thermometer-0: "\f2cb";
|
||||
@fa-var-thermometer-1: "\f2ca";
|
||||
@fa-var-thermometer-2: "\f2c9";
|
||||
@fa-var-thermometer-3: "\f2c8";
|
||||
@fa-var-thermometer-4: "\f2c7";
|
||||
@fa-var-thermometer-empty: "\f2cb";
|
||||
@fa-var-thermometer-full: "\f2c7";
|
||||
@fa-var-thermometer-half: "\f2c9";
|
||||
@fa-var-thermometer-quarter: "\f2ca";
|
||||
@fa-var-thermometer-three-quarters: "\f2c8";
|
||||
@fa-var-thumb-tack: "\f08d";
|
||||
@fa-var-thumbs-down: "\f165";
|
||||
@fa-var-thumbs-o-down: "\f088";
|
||||
|
|
@ -499,6 +696,8 @@
|
|||
@fa-var-times: "\f00d";
|
||||
@fa-var-times-circle: "\f057";
|
||||
@fa-var-times-circle-o: "\f05c";
|
||||
@fa-var-times-rectangle: "\f2d3";
|
||||
@fa-var-times-rectangle-o: "\f2d4";
|
||||
@fa-var-tint: "\f043";
|
||||
@fa-var-toggle-down: "\f150";
|
||||
@fa-var-toggle-left: "\f191";
|
||||
|
|
@ -506,10 +705,15 @@
|
|||
@fa-var-toggle-on: "\f205";
|
||||
@fa-var-toggle-right: "\f152";
|
||||
@fa-var-toggle-up: "\f151";
|
||||
@fa-var-trademark: "\f25c";
|
||||
@fa-var-train: "\f238";
|
||||
@fa-var-transgender: "\f224";
|
||||
@fa-var-transgender-alt: "\f225";
|
||||
@fa-var-trash: "\f1f8";
|
||||
@fa-var-trash-o: "\f014";
|
||||
@fa-var-tree: "\f1bb";
|
||||
@fa-var-trello: "\f181";
|
||||
@fa-var-tripadvisor: "\f262";
|
||||
@fa-var-trophy: "\f091";
|
||||
@fa-var-truck: "\f0d1";
|
||||
@fa-var-try: "\f195";
|
||||
|
|
@ -517,26 +721,45 @@
|
|||
@fa-var-tumblr: "\f173";
|
||||
@fa-var-tumblr-square: "\f174";
|
||||
@fa-var-turkish-lira: "\f195";
|
||||
@fa-var-tv: "\f26c";
|
||||
@fa-var-twitch: "\f1e8";
|
||||
@fa-var-twitter: "\f099";
|
||||
@fa-var-twitter-square: "\f081";
|
||||
@fa-var-umbrella: "\f0e9";
|
||||
@fa-var-underline: "\f0cd";
|
||||
@fa-var-undo: "\f0e2";
|
||||
@fa-var-universal-access: "\f29a";
|
||||
@fa-var-university: "\f19c";
|
||||
@fa-var-unlink: "\f127";
|
||||
@fa-var-unlock: "\f09c";
|
||||
@fa-var-unlock-alt: "\f13e";
|
||||
@fa-var-unsorted: "\f0dc";
|
||||
@fa-var-upload: "\f093";
|
||||
@fa-var-usb: "\f287";
|
||||
@fa-var-usd: "\f155";
|
||||
@fa-var-user: "\f007";
|
||||
@fa-var-user-circle: "\f2bd";
|
||||
@fa-var-user-circle-o: "\f2be";
|
||||
@fa-var-user-md: "\f0f0";
|
||||
@fa-var-user-o: "\f2c0";
|
||||
@fa-var-user-plus: "\f234";
|
||||
@fa-var-user-secret: "\f21b";
|
||||
@fa-var-user-times: "\f235";
|
||||
@fa-var-users: "\f0c0";
|
||||
@fa-var-vcard: "\f2bb";
|
||||
@fa-var-vcard-o: "\f2bc";
|
||||
@fa-var-venus: "\f221";
|
||||
@fa-var-venus-double: "\f226";
|
||||
@fa-var-venus-mars: "\f228";
|
||||
@fa-var-viacoin: "\f237";
|
||||
@fa-var-viadeo: "\f2a9";
|
||||
@fa-var-viadeo-square: "\f2aa";
|
||||
@fa-var-video-camera: "\f03d";
|
||||
@fa-var-vimeo: "\f27d";
|
||||
@fa-var-vimeo-square: "\f194";
|
||||
@fa-var-vine: "\f1ca";
|
||||
@fa-var-vk: "\f189";
|
||||
@fa-var-volume-control-phone: "\f2a0";
|
||||
@fa-var-volume-down: "\f027";
|
||||
@fa-var-volume-off: "\f026";
|
||||
@fa-var-volume-up: "\f028";
|
||||
|
|
@ -544,17 +767,33 @@
|
|||
@fa-var-wechat: "\f1d7";
|
||||
@fa-var-weibo: "\f18a";
|
||||
@fa-var-weixin: "\f1d7";
|
||||
@fa-var-whatsapp: "\f232";
|
||||
@fa-var-wheelchair: "\f193";
|
||||
@fa-var-wheelchair-alt: "\f29b";
|
||||
@fa-var-wifi: "\f1eb";
|
||||
@fa-var-wikipedia-w: "\f266";
|
||||
@fa-var-window-close: "\f2d3";
|
||||
@fa-var-window-close-o: "\f2d4";
|
||||
@fa-var-window-maximize: "\f2d0";
|
||||
@fa-var-window-minimize: "\f2d1";
|
||||
@fa-var-window-restore: "\f2d2";
|
||||
@fa-var-windows: "\f17a";
|
||||
@fa-var-won: "\f159";
|
||||
@fa-var-wordpress: "\f19a";
|
||||
@fa-var-wpbeginner: "\f297";
|
||||
@fa-var-wpexplorer: "\f2de";
|
||||
@fa-var-wpforms: "\f298";
|
||||
@fa-var-wrench: "\f0ad";
|
||||
@fa-var-xing: "\f168";
|
||||
@fa-var-xing-square: "\f169";
|
||||
@fa-var-y-combinator: "\f23b";
|
||||
@fa-var-y-combinator-square: "\f1d4";
|
||||
@fa-var-yahoo: "\f19e";
|
||||
@fa-var-yc: "\f23b";
|
||||
@fa-var-yc-square: "\f1d4";
|
||||
@fa-var-yelp: "\f1e9";
|
||||
@fa-var-yen: "\f157";
|
||||
@fa-var-yoast: "\f2b1";
|
||||
@fa-var-youtube: "\f167";
|
||||
@fa-var-youtube-play: "\f16a";
|
||||
@fa-var-youtube-square: "\f166";
|
||||
|
|
|
|||
|
|
@ -6,6 +6,11 @@
|
|||
animation: fa-spin 2s infinite linear;
|
||||
}
|
||||
|
||||
.#{$fa-css-prefix}-pulse {
|
||||
-webkit-animation: fa-spin 1s infinite steps(8);
|
||||
animation: fa-spin 1s infinite steps(8);
|
||||
}
|
||||
|
||||
@-webkit-keyframes fa-spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
|
|
@ -7,6 +7,15 @@
|
|||
border-radius: .1em;
|
||||
}
|
||||
|
||||
.#{$fa-css-prefix}-pull-left { float: left; }
|
||||
.#{$fa-css-prefix}-pull-right { float: right; }
|
||||
|
||||
.#{$fa-css-prefix} {
|
||||
&.#{$fa-css-prefix}-pull-left { margin-right: .3em; }
|
||||
&.#{$fa-css-prefix}-pull-right { margin-left: .3em; }
|
||||
}
|
||||
|
||||
/* Deprecated as of 4.4.0 */
|
||||
.pull-right { float: right; }
|
||||
.pull-left { float: left; }
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,10 @@
|
|||
|
||||
.#{$fa-css-prefix} {
|
||||
display: inline-block;
|
||||
font: normal normal normal 14px/1 FontAwesome; // shortening font declaration
|
||||
font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration
|
||||
font-size: inherit; // can't have font-size inherit on line above, so need to override
|
||||
text-rendering: auto; // optimizelegibility throws things off #1094
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,10 +158,12 @@
|
|||
.#{$fa-css-prefix}-bookmark-o:before { content: $fa-var-bookmark-o; }
|
||||
.#{$fa-css-prefix}-phone-square:before { content: $fa-var-phone-square; }
|
||||
.#{$fa-css-prefix}-twitter:before { content: $fa-var-twitter; }
|
||||
.#{$fa-css-prefix}-facebook-f:before,
|
||||
.#{$fa-css-prefix}-facebook:before { content: $fa-var-facebook; }
|
||||
.#{$fa-css-prefix}-github:before { content: $fa-var-github; }
|
||||
.#{$fa-css-prefix}-unlock:before { content: $fa-var-unlock; }
|
||||
.#{$fa-css-prefix}-credit-card:before { content: $fa-var-credit-card; }
|
||||
.#{$fa-css-prefix}-feed:before,
|
||||
.#{$fa-css-prefix}-rss:before { content: $fa-var-rss; }
|
||||
.#{$fa-css-prefix}-hdd-o:before { content: $fa-var-hdd-o; }
|
||||
.#{$fa-css-prefix}-bullhorn:before { content: $fa-var-bullhorn; }
|
||||
|
|
@ -397,7 +399,8 @@
|
|||
.#{$fa-css-prefix}-trello:before { content: $fa-var-trello; }
|
||||
.#{$fa-css-prefix}-female:before { content: $fa-var-female; }
|
||||
.#{$fa-css-prefix}-male:before { content: $fa-var-male; }
|
||||
.#{$fa-css-prefix}-gittip:before { content: $fa-var-gittip; }
|
||||
.#{$fa-css-prefix}-gittip:before,
|
||||
.#{$fa-css-prefix}-gratipay:before { content: $fa-var-gratipay; }
|
||||
.#{$fa-css-prefix}-sun-o:before { content: $fa-var-sun-o; }
|
||||
.#{$fa-css-prefix}-moon-o:before { content: $fa-var-moon-o; }
|
||||
.#{$fa-css-prefix}-archive:before { content: $fa-var-archive; }
|
||||
|
|
@ -435,7 +438,7 @@
|
|||
.#{$fa-css-prefix}-stumbleupon:before { content: $fa-var-stumbleupon; }
|
||||
.#{$fa-css-prefix}-delicious:before { content: $fa-var-delicious; }
|
||||
.#{$fa-css-prefix}-digg:before { content: $fa-var-digg; }
|
||||
.#{$fa-css-prefix}-pied-piper:before { content: $fa-var-pied-piper; }
|
||||
.#{$fa-css-prefix}-pied-piper-pp:before { content: $fa-var-pied-piper-pp; }
|
||||
.#{$fa-css-prefix}-pied-piper-alt:before { content: $fa-var-pied-piper-alt; }
|
||||
.#{$fa-css-prefix}-drupal:before { content: $fa-var-drupal; }
|
||||
.#{$fa-css-prefix}-joomla:before { content: $fa-var-joomla; }
|
||||
|
|
@ -485,11 +488,14 @@
|
|||
.#{$fa-css-prefix}-life-ring:before { content: $fa-var-life-ring; }
|
||||
.#{$fa-css-prefix}-circle-o-notch:before { content: $fa-var-circle-o-notch; }
|
||||
.#{$fa-css-prefix}-ra:before,
|
||||
.#{$fa-css-prefix}-resistance:before,
|
||||
.#{$fa-css-prefix}-rebel:before { content: $fa-var-rebel; }
|
||||
.#{$fa-css-prefix}-ge:before,
|
||||
.#{$fa-css-prefix}-empire:before { content: $fa-var-empire; }
|
||||
.#{$fa-css-prefix}-git-square:before { content: $fa-var-git-square; }
|
||||
.#{$fa-css-prefix}-git:before { content: $fa-var-git; }
|
||||
.#{$fa-css-prefix}-y-combinator-square:before,
|
||||
.#{$fa-css-prefix}-yc-square:before,
|
||||
.#{$fa-css-prefix}-hacker-news:before { content: $fa-var-hacker-news; }
|
||||
.#{$fa-css-prefix}-tencent-weibo:before { content: $fa-var-tencent-weibo; }
|
||||
.#{$fa-css-prefix}-qq:before { content: $fa-var-qq; }
|
||||
|
|
@ -550,3 +556,234 @@
|
|||
.#{$fa-css-prefix}-sheqel:before,
|
||||
.#{$fa-css-prefix}-ils:before { content: $fa-var-ils; }
|
||||
.#{$fa-css-prefix}-meanpath:before { content: $fa-var-meanpath; }
|
||||
.#{$fa-css-prefix}-buysellads:before { content: $fa-var-buysellads; }
|
||||
.#{$fa-css-prefix}-connectdevelop:before { content: $fa-var-connectdevelop; }
|
||||
.#{$fa-css-prefix}-dashcube:before { content: $fa-var-dashcube; }
|
||||
.#{$fa-css-prefix}-forumbee:before { content: $fa-var-forumbee; }
|
||||
.#{$fa-css-prefix}-leanpub:before { content: $fa-var-leanpub; }
|
||||
.#{$fa-css-prefix}-sellsy:before { content: $fa-var-sellsy; }
|
||||
.#{$fa-css-prefix}-shirtsinbulk:before { content: $fa-var-shirtsinbulk; }
|
||||
.#{$fa-css-prefix}-simplybuilt:before { content: $fa-var-simplybuilt; }
|
||||
.#{$fa-css-prefix}-skyatlas:before { content: $fa-var-skyatlas; }
|
||||
.#{$fa-css-prefix}-cart-plus:before { content: $fa-var-cart-plus; }
|
||||
.#{$fa-css-prefix}-cart-arrow-down:before { content: $fa-var-cart-arrow-down; }
|
||||
.#{$fa-css-prefix}-diamond:before { content: $fa-var-diamond; }
|
||||
.#{$fa-css-prefix}-ship:before { content: $fa-var-ship; }
|
||||
.#{$fa-css-prefix}-user-secret:before { content: $fa-var-user-secret; }
|
||||
.#{$fa-css-prefix}-motorcycle:before { content: $fa-var-motorcycle; }
|
||||
.#{$fa-css-prefix}-street-view:before { content: $fa-var-street-view; }
|
||||
.#{$fa-css-prefix}-heartbeat:before { content: $fa-var-heartbeat; }
|
||||
.#{$fa-css-prefix}-venus:before { content: $fa-var-venus; }
|
||||
.#{$fa-css-prefix}-mars:before { content: $fa-var-mars; }
|
||||
.#{$fa-css-prefix}-mercury:before { content: $fa-var-mercury; }
|
||||
.#{$fa-css-prefix}-intersex:before,
|
||||
.#{$fa-css-prefix}-transgender:before { content: $fa-var-transgender; }
|
||||
.#{$fa-css-prefix}-transgender-alt:before { content: $fa-var-transgender-alt; }
|
||||
.#{$fa-css-prefix}-venus-double:before { content: $fa-var-venus-double; }
|
||||
.#{$fa-css-prefix}-mars-double:before { content: $fa-var-mars-double; }
|
||||
.#{$fa-css-prefix}-venus-mars:before { content: $fa-var-venus-mars; }
|
||||
.#{$fa-css-prefix}-mars-stroke:before { content: $fa-var-mars-stroke; }
|
||||
.#{$fa-css-prefix}-mars-stroke-v:before { content: $fa-var-mars-stroke-v; }
|
||||
.#{$fa-css-prefix}-mars-stroke-h:before { content: $fa-var-mars-stroke-h; }
|
||||
.#{$fa-css-prefix}-neuter:before { content: $fa-var-neuter; }
|
||||
.#{$fa-css-prefix}-genderless:before { content: $fa-var-genderless; }
|
||||
.#{$fa-css-prefix}-facebook-official:before { content: $fa-var-facebook-official; }
|
||||
.#{$fa-css-prefix}-pinterest-p:before { content: $fa-var-pinterest-p; }
|
||||
.#{$fa-css-prefix}-whatsapp:before { content: $fa-var-whatsapp; }
|
||||
.#{$fa-css-prefix}-server:before { content: $fa-var-server; }
|
||||
.#{$fa-css-prefix}-user-plus:before { content: $fa-var-user-plus; }
|
||||
.#{$fa-css-prefix}-user-times:before { content: $fa-var-user-times; }
|
||||
.#{$fa-css-prefix}-hotel:before,
|
||||
.#{$fa-css-prefix}-bed:before { content: $fa-var-bed; }
|
||||
.#{$fa-css-prefix}-viacoin:before { content: $fa-var-viacoin; }
|
||||
.#{$fa-css-prefix}-train:before { content: $fa-var-train; }
|
||||
.#{$fa-css-prefix}-subway:before { content: $fa-var-subway; }
|
||||
.#{$fa-css-prefix}-medium:before { content: $fa-var-medium; }
|
||||
.#{$fa-css-prefix}-yc:before,
|
||||
.#{$fa-css-prefix}-y-combinator:before { content: $fa-var-y-combinator; }
|
||||
.#{$fa-css-prefix}-optin-monster:before { content: $fa-var-optin-monster; }
|
||||
.#{$fa-css-prefix}-opencart:before { content: $fa-var-opencart; }
|
||||
.#{$fa-css-prefix}-expeditedssl:before { content: $fa-var-expeditedssl; }
|
||||
.#{$fa-css-prefix}-battery-4:before,
|
||||
.#{$fa-css-prefix}-battery:before,
|
||||
.#{$fa-css-prefix}-battery-full:before { content: $fa-var-battery-full; }
|
||||
.#{$fa-css-prefix}-battery-3:before,
|
||||
.#{$fa-css-prefix}-battery-three-quarters:before { content: $fa-var-battery-three-quarters; }
|
||||
.#{$fa-css-prefix}-battery-2:before,
|
||||
.#{$fa-css-prefix}-battery-half:before { content: $fa-var-battery-half; }
|
||||
.#{$fa-css-prefix}-battery-1:before,
|
||||
.#{$fa-css-prefix}-battery-quarter:before { content: $fa-var-battery-quarter; }
|
||||
.#{$fa-css-prefix}-battery-0:before,
|
||||
.#{$fa-css-prefix}-battery-empty:before { content: $fa-var-battery-empty; }
|
||||
.#{$fa-css-prefix}-mouse-pointer:before { content: $fa-var-mouse-pointer; }
|
||||
.#{$fa-css-prefix}-i-cursor:before { content: $fa-var-i-cursor; }
|
||||
.#{$fa-css-prefix}-object-group:before { content: $fa-var-object-group; }
|
||||
.#{$fa-css-prefix}-object-ungroup:before { content: $fa-var-object-ungroup; }
|
||||
.#{$fa-css-prefix}-sticky-note:before { content: $fa-var-sticky-note; }
|
||||
.#{$fa-css-prefix}-sticky-note-o:before { content: $fa-var-sticky-note-o; }
|
||||
.#{$fa-css-prefix}-cc-jcb:before { content: $fa-var-cc-jcb; }
|
||||
.#{$fa-css-prefix}-cc-diners-club:before { content: $fa-var-cc-diners-club; }
|
||||
.#{$fa-css-prefix}-clone:before { content: $fa-var-clone; }
|
||||
.#{$fa-css-prefix}-balance-scale:before { content: $fa-var-balance-scale; }
|
||||
.#{$fa-css-prefix}-hourglass-o:before { content: $fa-var-hourglass-o; }
|
||||
.#{$fa-css-prefix}-hourglass-1:before,
|
||||
.#{$fa-css-prefix}-hourglass-start:before { content: $fa-var-hourglass-start; }
|
||||
.#{$fa-css-prefix}-hourglass-2:before,
|
||||
.#{$fa-css-prefix}-hourglass-half:before { content: $fa-var-hourglass-half; }
|
||||
.#{$fa-css-prefix}-hourglass-3:before,
|
||||
.#{$fa-css-prefix}-hourglass-end:before { content: $fa-var-hourglass-end; }
|
||||
.#{$fa-css-prefix}-hourglass:before { content: $fa-var-hourglass; }
|
||||
.#{$fa-css-prefix}-hand-grab-o:before,
|
||||
.#{$fa-css-prefix}-hand-rock-o:before { content: $fa-var-hand-rock-o; }
|
||||
.#{$fa-css-prefix}-hand-stop-o:before,
|
||||
.#{$fa-css-prefix}-hand-paper-o:before { content: $fa-var-hand-paper-o; }
|
||||
.#{$fa-css-prefix}-hand-scissors-o:before { content: $fa-var-hand-scissors-o; }
|
||||
.#{$fa-css-prefix}-hand-lizard-o:before { content: $fa-var-hand-lizard-o; }
|
||||
.#{$fa-css-prefix}-hand-spock-o:before { content: $fa-var-hand-spock-o; }
|
||||
.#{$fa-css-prefix}-hand-pointer-o:before { content: $fa-var-hand-pointer-o; }
|
||||
.#{$fa-css-prefix}-hand-peace-o:before { content: $fa-var-hand-peace-o; }
|
||||
.#{$fa-css-prefix}-trademark:before { content: $fa-var-trademark; }
|
||||
.#{$fa-css-prefix}-registered:before { content: $fa-var-registered; }
|
||||
.#{$fa-css-prefix}-creative-commons:before { content: $fa-var-creative-commons; }
|
||||
.#{$fa-css-prefix}-gg:before { content: $fa-var-gg; }
|
||||
.#{$fa-css-prefix}-gg-circle:before { content: $fa-var-gg-circle; }
|
||||
.#{$fa-css-prefix}-tripadvisor:before { content: $fa-var-tripadvisor; }
|
||||
.#{$fa-css-prefix}-odnoklassniki:before { content: $fa-var-odnoklassniki; }
|
||||
.#{$fa-css-prefix}-odnoklassniki-square:before { content: $fa-var-odnoklassniki-square; }
|
||||
.#{$fa-css-prefix}-get-pocket:before { content: $fa-var-get-pocket; }
|
||||
.#{$fa-css-prefix}-wikipedia-w:before { content: $fa-var-wikipedia-w; }
|
||||
.#{$fa-css-prefix}-safari:before { content: $fa-var-safari; }
|
||||
.#{$fa-css-prefix}-chrome:before { content: $fa-var-chrome; }
|
||||
.#{$fa-css-prefix}-firefox:before { content: $fa-var-firefox; }
|
||||
.#{$fa-css-prefix}-opera:before { content: $fa-var-opera; }
|
||||
.#{$fa-css-prefix}-internet-explorer:before { content: $fa-var-internet-explorer; }
|
||||
.#{$fa-css-prefix}-tv:before,
|
||||
.#{$fa-css-prefix}-television:before { content: $fa-var-television; }
|
||||
.#{$fa-css-prefix}-contao:before { content: $fa-var-contao; }
|
||||
.#{$fa-css-prefix}-500px:before { content: $fa-var-500px; }
|
||||
.#{$fa-css-prefix}-amazon:before { content: $fa-var-amazon; }
|
||||
.#{$fa-css-prefix}-calendar-plus-o:before { content: $fa-var-calendar-plus-o; }
|
||||
.#{$fa-css-prefix}-calendar-minus-o:before { content: $fa-var-calendar-minus-o; }
|
||||
.#{$fa-css-prefix}-calendar-times-o:before { content: $fa-var-calendar-times-o; }
|
||||
.#{$fa-css-prefix}-calendar-check-o:before { content: $fa-var-calendar-check-o; }
|
||||
.#{$fa-css-prefix}-industry:before { content: $fa-var-industry; }
|
||||
.#{$fa-css-prefix}-map-pin:before { content: $fa-var-map-pin; }
|
||||
.#{$fa-css-prefix}-map-signs:before { content: $fa-var-map-signs; }
|
||||
.#{$fa-css-prefix}-map-o:before { content: $fa-var-map-o; }
|
||||
.#{$fa-css-prefix}-map:before { content: $fa-var-map; }
|
||||
.#{$fa-css-prefix}-commenting:before { content: $fa-var-commenting; }
|
||||
.#{$fa-css-prefix}-commenting-o:before { content: $fa-var-commenting-o; }
|
||||
.#{$fa-css-prefix}-houzz:before { content: $fa-var-houzz; }
|
||||
.#{$fa-css-prefix}-vimeo:before { content: $fa-var-vimeo; }
|
||||
.#{$fa-css-prefix}-black-tie:before { content: $fa-var-black-tie; }
|
||||
.#{$fa-css-prefix}-fonticons:before { content: $fa-var-fonticons; }
|
||||
.#{$fa-css-prefix}-reddit-alien:before { content: $fa-var-reddit-alien; }
|
||||
.#{$fa-css-prefix}-edge:before { content: $fa-var-edge; }
|
||||
.#{$fa-css-prefix}-credit-card-alt:before { content: $fa-var-credit-card-alt; }
|
||||
.#{$fa-css-prefix}-codiepie:before { content: $fa-var-codiepie; }
|
||||
.#{$fa-css-prefix}-modx:before { content: $fa-var-modx; }
|
||||
.#{$fa-css-prefix}-fort-awesome:before { content: $fa-var-fort-awesome; }
|
||||
.#{$fa-css-prefix}-usb:before { content: $fa-var-usb; }
|
||||
.#{$fa-css-prefix}-product-hunt:before { content: $fa-var-product-hunt; }
|
||||
.#{$fa-css-prefix}-mixcloud:before { content: $fa-var-mixcloud; }
|
||||
.#{$fa-css-prefix}-scribd:before { content: $fa-var-scribd; }
|
||||
.#{$fa-css-prefix}-pause-circle:before { content: $fa-var-pause-circle; }
|
||||
.#{$fa-css-prefix}-pause-circle-o:before { content: $fa-var-pause-circle-o; }
|
||||
.#{$fa-css-prefix}-stop-circle:before { content: $fa-var-stop-circle; }
|
||||
.#{$fa-css-prefix}-stop-circle-o:before { content: $fa-var-stop-circle-o; }
|
||||
.#{$fa-css-prefix}-shopping-bag:before { content: $fa-var-shopping-bag; }
|
||||
.#{$fa-css-prefix}-shopping-basket:before { content: $fa-var-shopping-basket; }
|
||||
.#{$fa-css-prefix}-hashtag:before { content: $fa-var-hashtag; }
|
||||
.#{$fa-css-prefix}-bluetooth:before { content: $fa-var-bluetooth; }
|
||||
.#{$fa-css-prefix}-bluetooth-b:before { content: $fa-var-bluetooth-b; }
|
||||
.#{$fa-css-prefix}-percent:before { content: $fa-var-percent; }
|
||||
.#{$fa-css-prefix}-gitlab:before { content: $fa-var-gitlab; }
|
||||
.#{$fa-css-prefix}-wpbeginner:before { content: $fa-var-wpbeginner; }
|
||||
.#{$fa-css-prefix}-wpforms:before { content: $fa-var-wpforms; }
|
||||
.#{$fa-css-prefix}-envira:before { content: $fa-var-envira; }
|
||||
.#{$fa-css-prefix}-universal-access:before { content: $fa-var-universal-access; }
|
||||
.#{$fa-css-prefix}-wheelchair-alt:before { content: $fa-var-wheelchair-alt; }
|
||||
.#{$fa-css-prefix}-question-circle-o:before { content: $fa-var-question-circle-o; }
|
||||
.#{$fa-css-prefix}-blind:before { content: $fa-var-blind; }
|
||||
.#{$fa-css-prefix}-audio-description:before { content: $fa-var-audio-description; }
|
||||
.#{$fa-css-prefix}-volume-control-phone:before { content: $fa-var-volume-control-phone; }
|
||||
.#{$fa-css-prefix}-braille:before { content: $fa-var-braille; }
|
||||
.#{$fa-css-prefix}-assistive-listening-systems:before { content: $fa-var-assistive-listening-systems; }
|
||||
.#{$fa-css-prefix}-asl-interpreting:before,
|
||||
.#{$fa-css-prefix}-american-sign-language-interpreting:before { content: $fa-var-american-sign-language-interpreting; }
|
||||
.#{$fa-css-prefix}-deafness:before,
|
||||
.#{$fa-css-prefix}-hard-of-hearing:before,
|
||||
.#{$fa-css-prefix}-deaf:before { content: $fa-var-deaf; }
|
||||
.#{$fa-css-prefix}-glide:before { content: $fa-var-glide; }
|
||||
.#{$fa-css-prefix}-glide-g:before { content: $fa-var-glide-g; }
|
||||
.#{$fa-css-prefix}-signing:before,
|
||||
.#{$fa-css-prefix}-sign-language:before { content: $fa-var-sign-language; }
|
||||
.#{$fa-css-prefix}-low-vision:before { content: $fa-var-low-vision; }
|
||||
.#{$fa-css-prefix}-viadeo:before { content: $fa-var-viadeo; }
|
||||
.#{$fa-css-prefix}-viadeo-square:before { content: $fa-var-viadeo-square; }
|
||||
.#{$fa-css-prefix}-snapchat:before { content: $fa-var-snapchat; }
|
||||
.#{$fa-css-prefix}-snapchat-ghost:before { content: $fa-var-snapchat-ghost; }
|
||||
.#{$fa-css-prefix}-snapchat-square:before { content: $fa-var-snapchat-square; }
|
||||
.#{$fa-css-prefix}-pied-piper:before { content: $fa-var-pied-piper; }
|
||||
.#{$fa-css-prefix}-first-order:before { content: $fa-var-first-order; }
|
||||
.#{$fa-css-prefix}-yoast:before { content: $fa-var-yoast; }
|
||||
.#{$fa-css-prefix}-themeisle:before { content: $fa-var-themeisle; }
|
||||
.#{$fa-css-prefix}-google-plus-circle:before,
|
||||
.#{$fa-css-prefix}-google-plus-official:before { content: $fa-var-google-plus-official; }
|
||||
.#{$fa-css-prefix}-fa:before,
|
||||
.#{$fa-css-prefix}-font-awesome:before { content: $fa-var-font-awesome; }
|
||||
.#{$fa-css-prefix}-handshake-o:before { content: $fa-var-handshake-o; }
|
||||
.#{$fa-css-prefix}-envelope-open:before { content: $fa-var-envelope-open; }
|
||||
.#{$fa-css-prefix}-envelope-open-o:before { content: $fa-var-envelope-open-o; }
|
||||
.#{$fa-css-prefix}-linode:before { content: $fa-var-linode; }
|
||||
.#{$fa-css-prefix}-address-book:before { content: $fa-var-address-book; }
|
||||
.#{$fa-css-prefix}-address-book-o:before { content: $fa-var-address-book-o; }
|
||||
.#{$fa-css-prefix}-vcard:before,
|
||||
.#{$fa-css-prefix}-address-card:before { content: $fa-var-address-card; }
|
||||
.#{$fa-css-prefix}-vcard-o:before,
|
||||
.#{$fa-css-prefix}-address-card-o:before { content: $fa-var-address-card-o; }
|
||||
.#{$fa-css-prefix}-user-circle:before { content: $fa-var-user-circle; }
|
||||
.#{$fa-css-prefix}-user-circle-o:before { content: $fa-var-user-circle-o; }
|
||||
.#{$fa-css-prefix}-user-o:before { content: $fa-var-user-o; }
|
||||
.#{$fa-css-prefix}-id-badge:before { content: $fa-var-id-badge; }
|
||||
.#{$fa-css-prefix}-drivers-license:before,
|
||||
.#{$fa-css-prefix}-id-card:before { content: $fa-var-id-card; }
|
||||
.#{$fa-css-prefix}-drivers-license-o:before,
|
||||
.#{$fa-css-prefix}-id-card-o:before { content: $fa-var-id-card-o; }
|
||||
.#{$fa-css-prefix}-quora:before { content: $fa-var-quora; }
|
||||
.#{$fa-css-prefix}-free-code-camp:before { content: $fa-var-free-code-camp; }
|
||||
.#{$fa-css-prefix}-telegram:before { content: $fa-var-telegram; }
|
||||
.#{$fa-css-prefix}-thermometer-4:before,
|
||||
.#{$fa-css-prefix}-thermometer:before,
|
||||
.#{$fa-css-prefix}-thermometer-full:before { content: $fa-var-thermometer-full; }
|
||||
.#{$fa-css-prefix}-thermometer-3:before,
|
||||
.#{$fa-css-prefix}-thermometer-three-quarters:before { content: $fa-var-thermometer-three-quarters; }
|
||||
.#{$fa-css-prefix}-thermometer-2:before,
|
||||
.#{$fa-css-prefix}-thermometer-half:before { content: $fa-var-thermometer-half; }
|
||||
.#{$fa-css-prefix}-thermometer-1:before,
|
||||
.#{$fa-css-prefix}-thermometer-quarter:before { content: $fa-var-thermometer-quarter; }
|
||||
.#{$fa-css-prefix}-thermometer-0:before,
|
||||
.#{$fa-css-prefix}-thermometer-empty:before { content: $fa-var-thermometer-empty; }
|
||||
.#{$fa-css-prefix}-shower:before { content: $fa-var-shower; }
|
||||
.#{$fa-css-prefix}-bathtub:before,
|
||||
.#{$fa-css-prefix}-s15:before,
|
||||
.#{$fa-css-prefix}-bath:before { content: $fa-var-bath; }
|
||||
.#{$fa-css-prefix}-podcast:before { content: $fa-var-podcast; }
|
||||
.#{$fa-css-prefix}-window-maximize:before { content: $fa-var-window-maximize; }
|
||||
.#{$fa-css-prefix}-window-minimize:before { content: $fa-var-window-minimize; }
|
||||
.#{$fa-css-prefix}-window-restore:before { content: $fa-var-window-restore; }
|
||||
.#{$fa-css-prefix}-times-rectangle:before,
|
||||
.#{$fa-css-prefix}-window-close:before { content: $fa-var-window-close; }
|
||||
.#{$fa-css-prefix}-times-rectangle-o:before,
|
||||
.#{$fa-css-prefix}-window-close-o:before { content: $fa-var-window-close-o; }
|
||||
.#{$fa-css-prefix}-bandcamp:before { content: $fa-var-bandcamp; }
|
||||
.#{$fa-css-prefix}-grav:before { content: $fa-var-grav; }
|
||||
.#{$fa-css-prefix}-etsy:before { content: $fa-var-etsy; }
|
||||
.#{$fa-css-prefix}-imdb:before { content: $fa-var-imdb; }
|
||||
.#{$fa-css-prefix}-ravelry:before { content: $fa-var-ravelry; }
|
||||
.#{$fa-css-prefix}-eercast:before { content: $fa-var-eercast; }
|
||||
.#{$fa-css-prefix}-microchip:before { content: $fa-var-microchip; }
|
||||
.#{$fa-css-prefix}-snowflake-o:before { content: $fa-var-snowflake-o; }
|
||||
.#{$fa-css-prefix}-superpowers:before { content: $fa-var-superpowers; }
|
||||
.#{$fa-css-prefix}-wpexplorer:before { content: $fa-var-wpexplorer; }
|
||||
.#{$fa-css-prefix}-meetup:before { content: $fa-var-meetup; }
|
||||
|
|
|
|||
|
|
@ -3,23 +3,58 @@
|
|||
|
||||
@mixin fa-icon() {
|
||||
display: inline-block;
|
||||
font: normal normal normal 14px/1 FontAwesome; // shortening font declaration
|
||||
font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration
|
||||
font-size: inherit; // can't have font-size inherit on line above, so need to override
|
||||
text-rendering: auto; // optimizelegibility throws things off #1094
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
}
|
||||
|
||||
@mixin fa-icon-rotate($degrees, $rotation) {
|
||||
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation});
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})";
|
||||
-webkit-transform: rotate($degrees);
|
||||
-ms-transform: rotate($degrees);
|
||||
transform: rotate($degrees);
|
||||
}
|
||||
|
||||
@mixin fa-icon-flip($horiz, $vert, $rotation) {
|
||||
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation});
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)";
|
||||
-webkit-transform: scale($horiz, $vert);
|
||||
-ms-transform: scale($horiz, $vert);
|
||||
transform: scale($horiz, $vert);
|
||||
}
|
||||
|
||||
|
||||
// Only display content to screen readers. A la Bootstrap 4.
|
||||
//
|
||||
// See: http://a11yproject.com/posts/how-to-hide-content/
|
||||
|
||||
@mixin sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0,0,0,0);
|
||||
border: 0;
|
||||
}
|
||||
|
||||
// Use in conjunction with .sr-only to only display content when it's focused.
|
||||
//
|
||||
// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
|
||||
//
|
||||
// Credit: HTML5 Boilerplate
|
||||
|
||||
@mixin sr-only-focusable {
|
||||
&:active,
|
||||
&:focus {
|
||||
position: static;
|
||||
width: auto;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
overflow: visible;
|
||||
clip: auto;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@
|
|||
font-family: 'FontAwesome';
|
||||
src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}');
|
||||
src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'),
|
||||
url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'),
|
||||
url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'),
|
||||
url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'),
|
||||
url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg');
|
||||
//src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
|
||||
// src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
|
|
|||
5
assets/font/fonts-awesome/scss/_screen-reader.scss
Normal file
5
assets/font/fonts-awesome/scss/_screen-reader.scss
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// Screen Readers
|
||||
// -------------------------
|
||||
|
||||
.sr-only { @include sr-only(); }
|
||||
.sr-only-focusable { @include sr-only-focusable(); }
|
||||
|
|
@ -2,20 +2,29 @@
|
|||
// --------------------------
|
||||
|
||||
$fa-font-path: "../fonts" !default;
|
||||
//$fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.2.0/fonts" !default; // for referencing Bootstrap CDN font files directly
|
||||
$fa-font-size-base: 14px !default;
|
||||
$fa-line-height-base: 1 !default;
|
||||
//$fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.7.0/fonts" !default; // for referencing Bootstrap CDN font files directly
|
||||
$fa-css-prefix: fa !default;
|
||||
$fa-version: "4.2.0" !default;
|
||||
$fa-version: "4.7.0" !default;
|
||||
$fa-border-color: #eee !default;
|
||||
$fa-inverse: #fff !default;
|
||||
$fa-li-width: (30em / 14) !default;
|
||||
|
||||
$fa-var-500px: "\f26e";
|
||||
$fa-var-address-book: "\f2b9";
|
||||
$fa-var-address-book-o: "\f2ba";
|
||||
$fa-var-address-card: "\f2bb";
|
||||
$fa-var-address-card-o: "\f2bc";
|
||||
$fa-var-adjust: "\f042";
|
||||
$fa-var-adn: "\f170";
|
||||
$fa-var-align-center: "\f037";
|
||||
$fa-var-align-justify: "\f039";
|
||||
$fa-var-align-left: "\f036";
|
||||
$fa-var-align-right: "\f038";
|
||||
$fa-var-amazon: "\f270";
|
||||
$fa-var-ambulance: "\f0f9";
|
||||
$fa-var-american-sign-language-interpreting: "\f2a3";
|
||||
$fa-var-anchor: "\f13d";
|
||||
$fa-var-android: "\f17b";
|
||||
$fa-var-angellist: "\f209";
|
||||
|
|
@ -46,16 +55,35 @@ $fa-var-arrows: "\f047";
|
|||
$fa-var-arrows-alt: "\f0b2";
|
||||
$fa-var-arrows-h: "\f07e";
|
||||
$fa-var-arrows-v: "\f07d";
|
||||
$fa-var-asl-interpreting: "\f2a3";
|
||||
$fa-var-assistive-listening-systems: "\f2a2";
|
||||
$fa-var-asterisk: "\f069";
|
||||
$fa-var-at: "\f1fa";
|
||||
$fa-var-audio-description: "\f29e";
|
||||
$fa-var-automobile: "\f1b9";
|
||||
$fa-var-backward: "\f04a";
|
||||
$fa-var-balance-scale: "\f24e";
|
||||
$fa-var-ban: "\f05e";
|
||||
$fa-var-bandcamp: "\f2d5";
|
||||
$fa-var-bank: "\f19c";
|
||||
$fa-var-bar-chart: "\f080";
|
||||
$fa-var-bar-chart-o: "\f080";
|
||||
$fa-var-barcode: "\f02a";
|
||||
$fa-var-bars: "\f0c9";
|
||||
$fa-var-bath: "\f2cd";
|
||||
$fa-var-bathtub: "\f2cd";
|
||||
$fa-var-battery: "\f240";
|
||||
$fa-var-battery-0: "\f244";
|
||||
$fa-var-battery-1: "\f243";
|
||||
$fa-var-battery-2: "\f242";
|
||||
$fa-var-battery-3: "\f241";
|
||||
$fa-var-battery-4: "\f240";
|
||||
$fa-var-battery-empty: "\f244";
|
||||
$fa-var-battery-full: "\f240";
|
||||
$fa-var-battery-half: "\f242";
|
||||
$fa-var-battery-quarter: "\f243";
|
||||
$fa-var-battery-three-quarters: "\f241";
|
||||
$fa-var-bed: "\f236";
|
||||
$fa-var-beer: "\f0fc";
|
||||
$fa-var-behance: "\f1b4";
|
||||
$fa-var-behance-square: "\f1b5";
|
||||
|
|
@ -69,12 +97,17 @@ $fa-var-birthday-cake: "\f1fd";
|
|||
$fa-var-bitbucket: "\f171";
|
||||
$fa-var-bitbucket-square: "\f172";
|
||||
$fa-var-bitcoin: "\f15a";
|
||||
$fa-var-black-tie: "\f27e";
|
||||
$fa-var-blind: "\f29d";
|
||||
$fa-var-bluetooth: "\f293";
|
||||
$fa-var-bluetooth-b: "\f294";
|
||||
$fa-var-bold: "\f032";
|
||||
$fa-var-bolt: "\f0e7";
|
||||
$fa-var-bomb: "\f1e2";
|
||||
$fa-var-book: "\f02d";
|
||||
$fa-var-bookmark: "\f02e";
|
||||
$fa-var-bookmark-o: "\f097";
|
||||
$fa-var-braille: "\f2a1";
|
||||
$fa-var-briefcase: "\f0b1";
|
||||
$fa-var-btc: "\f15a";
|
||||
$fa-var-bug: "\f188";
|
||||
|
|
@ -83,10 +116,15 @@ $fa-var-building-o: "\f0f7";
|
|||
$fa-var-bullhorn: "\f0a1";
|
||||
$fa-var-bullseye: "\f140";
|
||||
$fa-var-bus: "\f207";
|
||||
$fa-var-buysellads: "\f20d";
|
||||
$fa-var-cab: "\f1ba";
|
||||
$fa-var-calculator: "\f1ec";
|
||||
$fa-var-calendar: "\f073";
|
||||
$fa-var-calendar-check-o: "\f274";
|
||||
$fa-var-calendar-minus-o: "\f272";
|
||||
$fa-var-calendar-o: "\f133";
|
||||
$fa-var-calendar-plus-o: "\f271";
|
||||
$fa-var-calendar-times-o: "\f273";
|
||||
$fa-var-camera: "\f030";
|
||||
$fa-var-camera-retro: "\f083";
|
||||
$fa-var-car: "\f1b9";
|
||||
|
|
@ -98,9 +136,13 @@ $fa-var-caret-square-o-left: "\f191";
|
|||
$fa-var-caret-square-o-right: "\f152";
|
||||
$fa-var-caret-square-o-up: "\f151";
|
||||
$fa-var-caret-up: "\f0d8";
|
||||
$fa-var-cart-arrow-down: "\f218";
|
||||
$fa-var-cart-plus: "\f217";
|
||||
$fa-var-cc: "\f20a";
|
||||
$fa-var-cc-amex: "\f1f3";
|
||||
$fa-var-cc-diners-club: "\f24c";
|
||||
$fa-var-cc-discover: "\f1f2";
|
||||
$fa-var-cc-jcb: "\f24b";
|
||||
$fa-var-cc-mastercard: "\f1f1";
|
||||
$fa-var-cc-paypal: "\f1f4";
|
||||
$fa-var-cc-stripe: "\f1f5";
|
||||
|
|
@ -122,12 +164,14 @@ $fa-var-chevron-left: "\f053";
|
|||
$fa-var-chevron-right: "\f054";
|
||||
$fa-var-chevron-up: "\f077";
|
||||
$fa-var-child: "\f1ae";
|
||||
$fa-var-chrome: "\f268";
|
||||
$fa-var-circle: "\f111";
|
||||
$fa-var-circle-o: "\f10c";
|
||||
$fa-var-circle-o-notch: "\f1ce";
|
||||
$fa-var-circle-thin: "\f1db";
|
||||
$fa-var-clipboard: "\f0ea";
|
||||
$fa-var-clock-o: "\f017";
|
||||
$fa-var-clone: "\f24d";
|
||||
$fa-var-close: "\f00d";
|
||||
$fa-var-cloud: "\f0c2";
|
||||
$fa-var-cloud-download: "\f0ed";
|
||||
|
|
@ -136,19 +180,26 @@ $fa-var-cny: "\f157";
|
|||
$fa-var-code: "\f121";
|
||||
$fa-var-code-fork: "\f126";
|
||||
$fa-var-codepen: "\f1cb";
|
||||
$fa-var-codiepie: "\f284";
|
||||
$fa-var-coffee: "\f0f4";
|
||||
$fa-var-cog: "\f013";
|
||||
$fa-var-cogs: "\f085";
|
||||
$fa-var-columns: "\f0db";
|
||||
$fa-var-comment: "\f075";
|
||||
$fa-var-comment-o: "\f0e5";
|
||||
$fa-var-commenting: "\f27a";
|
||||
$fa-var-commenting-o: "\f27b";
|
||||
$fa-var-comments: "\f086";
|
||||
$fa-var-comments-o: "\f0e6";
|
||||
$fa-var-compass: "\f14e";
|
||||
$fa-var-compress: "\f066";
|
||||
$fa-var-connectdevelop: "\f20e";
|
||||
$fa-var-contao: "\f26d";
|
||||
$fa-var-copy: "\f0c5";
|
||||
$fa-var-copyright: "\f1f9";
|
||||
$fa-var-creative-commons: "\f25e";
|
||||
$fa-var-credit-card: "\f09d";
|
||||
$fa-var-credit-card-alt: "\f283";
|
||||
$fa-var-crop: "\f125";
|
||||
$fa-var-crosshairs: "\f05b";
|
||||
$fa-var-css3: "\f13c";
|
||||
|
|
@ -157,27 +208,39 @@ $fa-var-cubes: "\f1b3";
|
|||
$fa-var-cut: "\f0c4";
|
||||
$fa-var-cutlery: "\f0f5";
|
||||
$fa-var-dashboard: "\f0e4";
|
||||
$fa-var-dashcube: "\f210";
|
||||
$fa-var-database: "\f1c0";
|
||||
$fa-var-deaf: "\f2a4";
|
||||
$fa-var-deafness: "\f2a4";
|
||||
$fa-var-dedent: "\f03b";
|
||||
$fa-var-delicious: "\f1a5";
|
||||
$fa-var-desktop: "\f108";
|
||||
$fa-var-deviantart: "\f1bd";
|
||||
$fa-var-diamond: "\f219";
|
||||
$fa-var-digg: "\f1a6";
|
||||
$fa-var-dollar: "\f155";
|
||||
$fa-var-dot-circle-o: "\f192";
|
||||
$fa-var-download: "\f019";
|
||||
$fa-var-dribbble: "\f17d";
|
||||
$fa-var-drivers-license: "\f2c2";
|
||||
$fa-var-drivers-license-o: "\f2c3";
|
||||
$fa-var-dropbox: "\f16b";
|
||||
$fa-var-drupal: "\f1a9";
|
||||
$fa-var-edge: "\f282";
|
||||
$fa-var-edit: "\f044";
|
||||
$fa-var-eercast: "\f2da";
|
||||
$fa-var-eject: "\f052";
|
||||
$fa-var-ellipsis-h: "\f141";
|
||||
$fa-var-ellipsis-v: "\f142";
|
||||
$fa-var-empire: "\f1d1";
|
||||
$fa-var-envelope: "\f0e0";
|
||||
$fa-var-envelope-o: "\f003";
|
||||
$fa-var-envelope-open: "\f2b6";
|
||||
$fa-var-envelope-open-o: "\f2b7";
|
||||
$fa-var-envelope-square: "\f199";
|
||||
$fa-var-envira: "\f299";
|
||||
$fa-var-eraser: "\f12d";
|
||||
$fa-var-etsy: "\f2d7";
|
||||
$fa-var-eur: "\f153";
|
||||
$fa-var-euro: "\f153";
|
||||
$fa-var-exchange: "\f0ec";
|
||||
|
|
@ -185,16 +248,21 @@ $fa-var-exclamation: "\f12a";
|
|||
$fa-var-exclamation-circle: "\f06a";
|
||||
$fa-var-exclamation-triangle: "\f071";
|
||||
$fa-var-expand: "\f065";
|
||||
$fa-var-expeditedssl: "\f23e";
|
||||
$fa-var-external-link: "\f08e";
|
||||
$fa-var-external-link-square: "\f14c";
|
||||
$fa-var-eye: "\f06e";
|
||||
$fa-var-eye-slash: "\f070";
|
||||
$fa-var-eyedropper: "\f1fb";
|
||||
$fa-var-fa: "\f2b4";
|
||||
$fa-var-facebook: "\f09a";
|
||||
$fa-var-facebook-f: "\f09a";
|
||||
$fa-var-facebook-official: "\f230";
|
||||
$fa-var-facebook-square: "\f082";
|
||||
$fa-var-fast-backward: "\f049";
|
||||
$fa-var-fast-forward: "\f050";
|
||||
$fa-var-fax: "\f1ac";
|
||||
$fa-var-feed: "\f09e";
|
||||
$fa-var-female: "\f182";
|
||||
$fa-var-fighter-jet: "\f0fb";
|
||||
$fa-var-file: "\f15b";
|
||||
|
|
@ -220,6 +288,8 @@ $fa-var-film: "\f008";
|
|||
$fa-var-filter: "\f0b0";
|
||||
$fa-var-fire: "\f06d";
|
||||
$fa-var-fire-extinguisher: "\f134";
|
||||
$fa-var-firefox: "\f269";
|
||||
$fa-var-first-order: "\f2b0";
|
||||
$fa-var-flag: "\f024";
|
||||
$fa-var-flag-checkered: "\f11e";
|
||||
$fa-var-flag-o: "\f11d";
|
||||
|
|
@ -232,8 +302,13 @@ $fa-var-folder-o: "\f114";
|
|||
$fa-var-folder-open: "\f07c";
|
||||
$fa-var-folder-open-o: "\f115";
|
||||
$fa-var-font: "\f031";
|
||||
$fa-var-font-awesome: "\f2b4";
|
||||
$fa-var-fonticons: "\f280";
|
||||
$fa-var-fort-awesome: "\f286";
|
||||
$fa-var-forumbee: "\f211";
|
||||
$fa-var-forward: "\f04e";
|
||||
$fa-var-foursquare: "\f180";
|
||||
$fa-var-free-code-camp: "\f2c5";
|
||||
$fa-var-frown-o: "\f119";
|
||||
$fa-var-futbol-o: "\f1e3";
|
||||
$fa-var-gamepad: "\f11b";
|
||||
|
|
@ -242,45 +317,87 @@ $fa-var-gbp: "\f154";
|
|||
$fa-var-ge: "\f1d1";
|
||||
$fa-var-gear: "\f013";
|
||||
$fa-var-gears: "\f085";
|
||||
$fa-var-genderless: "\f22d";
|
||||
$fa-var-get-pocket: "\f265";
|
||||
$fa-var-gg: "\f260";
|
||||
$fa-var-gg-circle: "\f261";
|
||||
$fa-var-gift: "\f06b";
|
||||
$fa-var-git: "\f1d3";
|
||||
$fa-var-git-square: "\f1d2";
|
||||
$fa-var-github: "\f09b";
|
||||
$fa-var-github-alt: "\f113";
|
||||
$fa-var-github-square: "\f092";
|
||||
$fa-var-gitlab: "\f296";
|
||||
$fa-var-gittip: "\f184";
|
||||
$fa-var-glass: "\f000";
|
||||
$fa-var-glide: "\f2a5";
|
||||
$fa-var-glide-g: "\f2a6";
|
||||
$fa-var-globe: "\f0ac";
|
||||
$fa-var-google: "\f1a0";
|
||||
$fa-var-google-plus: "\f0d5";
|
||||
$fa-var-google-plus-circle: "\f2b3";
|
||||
$fa-var-google-plus-official: "\f2b3";
|
||||
$fa-var-google-plus-square: "\f0d4";
|
||||
$fa-var-google-wallet: "\f1ee";
|
||||
$fa-var-graduation-cap: "\f19d";
|
||||
$fa-var-gratipay: "\f184";
|
||||
$fa-var-grav: "\f2d6";
|
||||
$fa-var-group: "\f0c0";
|
||||
$fa-var-h-square: "\f0fd";
|
||||
$fa-var-hacker-news: "\f1d4";
|
||||
$fa-var-hand-grab-o: "\f255";
|
||||
$fa-var-hand-lizard-o: "\f258";
|
||||
$fa-var-hand-o-down: "\f0a7";
|
||||
$fa-var-hand-o-left: "\f0a5";
|
||||
$fa-var-hand-o-right: "\f0a4";
|
||||
$fa-var-hand-o-up: "\f0a6";
|
||||
$fa-var-hand-paper-o: "\f256";
|
||||
$fa-var-hand-peace-o: "\f25b";
|
||||
$fa-var-hand-pointer-o: "\f25a";
|
||||
$fa-var-hand-rock-o: "\f255";
|
||||
$fa-var-hand-scissors-o: "\f257";
|
||||
$fa-var-hand-spock-o: "\f259";
|
||||
$fa-var-hand-stop-o: "\f256";
|
||||
$fa-var-handshake-o: "\f2b5";
|
||||
$fa-var-hard-of-hearing: "\f2a4";
|
||||
$fa-var-hashtag: "\f292";
|
||||
$fa-var-hdd-o: "\f0a0";
|
||||
$fa-var-header: "\f1dc";
|
||||
$fa-var-headphones: "\f025";
|
||||
$fa-var-heart: "\f004";
|
||||
$fa-var-heart-o: "\f08a";
|
||||
$fa-var-heartbeat: "\f21e";
|
||||
$fa-var-history: "\f1da";
|
||||
$fa-var-home: "\f015";
|
||||
$fa-var-hospital-o: "\f0f8";
|
||||
$fa-var-hotel: "\f236";
|
||||
$fa-var-hourglass: "\f254";
|
||||
$fa-var-hourglass-1: "\f251";
|
||||
$fa-var-hourglass-2: "\f252";
|
||||
$fa-var-hourglass-3: "\f253";
|
||||
$fa-var-hourglass-end: "\f253";
|
||||
$fa-var-hourglass-half: "\f252";
|
||||
$fa-var-hourglass-o: "\f250";
|
||||
$fa-var-hourglass-start: "\f251";
|
||||
$fa-var-houzz: "\f27c";
|
||||
$fa-var-html5: "\f13b";
|
||||
$fa-var-i-cursor: "\f246";
|
||||
$fa-var-id-badge: "\f2c1";
|
||||
$fa-var-id-card: "\f2c2";
|
||||
$fa-var-id-card-o: "\f2c3";
|
||||
$fa-var-ils: "\f20b";
|
||||
$fa-var-image: "\f03e";
|
||||
$fa-var-imdb: "\f2d8";
|
||||
$fa-var-inbox: "\f01c";
|
||||
$fa-var-indent: "\f03c";
|
||||
$fa-var-industry: "\f275";
|
||||
$fa-var-info: "\f129";
|
||||
$fa-var-info-circle: "\f05a";
|
||||
$fa-var-inr: "\f156";
|
||||
$fa-var-instagram: "\f16d";
|
||||
$fa-var-institution: "\f19c";
|
||||
$fa-var-internet-explorer: "\f26b";
|
||||
$fa-var-intersex: "\f224";
|
||||
$fa-var-ioxhost: "\f208";
|
||||
$fa-var-italic: "\f033";
|
||||
$fa-var-joomla: "\f1aa";
|
||||
|
|
@ -294,6 +411,7 @@ $fa-var-laptop: "\f109";
|
|||
$fa-var-lastfm: "\f202";
|
||||
$fa-var-lastfm-square: "\f203";
|
||||
$fa-var-leaf: "\f06c";
|
||||
$fa-var-leanpub: "\f212";
|
||||
$fa-var-legal: "\f0e3";
|
||||
$fa-var-lemon-o: "\f094";
|
||||
$fa-var-level-down: "\f149";
|
||||
|
|
@ -307,6 +425,7 @@ $fa-var-line-chart: "\f201";
|
|||
$fa-var-link: "\f0c1";
|
||||
$fa-var-linkedin: "\f0e1";
|
||||
$fa-var-linkedin-square: "\f08c";
|
||||
$fa-var-linode: "\f2b8";
|
||||
$fa-var-linux: "\f17c";
|
||||
$fa-var-list: "\f03a";
|
||||
$fa-var-list-alt: "\f022";
|
||||
|
|
@ -318,32 +437,58 @@ $fa-var-long-arrow-down: "\f175";
|
|||
$fa-var-long-arrow-left: "\f177";
|
||||
$fa-var-long-arrow-right: "\f178";
|
||||
$fa-var-long-arrow-up: "\f176";
|
||||
$fa-var-low-vision: "\f2a8";
|
||||
$fa-var-magic: "\f0d0";
|
||||
$fa-var-magnet: "\f076";
|
||||
$fa-var-mail-forward: "\f064";
|
||||
$fa-var-mail-reply: "\f112";
|
||||
$fa-var-mail-reply-all: "\f122";
|
||||
$fa-var-male: "\f183";
|
||||
$fa-var-map: "\f279";
|
||||
$fa-var-map-marker: "\f041";
|
||||
$fa-var-map-o: "\f278";
|
||||
$fa-var-map-pin: "\f276";
|
||||
$fa-var-map-signs: "\f277";
|
||||
$fa-var-mars: "\f222";
|
||||
$fa-var-mars-double: "\f227";
|
||||
$fa-var-mars-stroke: "\f229";
|
||||
$fa-var-mars-stroke-h: "\f22b";
|
||||
$fa-var-mars-stroke-v: "\f22a";
|
||||
$fa-var-maxcdn: "\f136";
|
||||
$fa-var-meanpath: "\f20c";
|
||||
$fa-var-medium: "\f23a";
|
||||
$fa-var-medkit: "\f0fa";
|
||||
$fa-var-meetup: "\f2e0";
|
||||
$fa-var-meh-o: "\f11a";
|
||||
$fa-var-mercury: "\f223";
|
||||
$fa-var-microchip: "\f2db";
|
||||
$fa-var-microphone: "\f130";
|
||||
$fa-var-microphone-slash: "\f131";
|
||||
$fa-var-minus: "\f068";
|
||||
$fa-var-minus-circle: "\f056";
|
||||
$fa-var-minus-square: "\f146";
|
||||
$fa-var-minus-square-o: "\f147";
|
||||
$fa-var-mixcloud: "\f289";
|
||||
$fa-var-mobile: "\f10b";
|
||||
$fa-var-mobile-phone: "\f10b";
|
||||
$fa-var-modx: "\f285";
|
||||
$fa-var-money: "\f0d6";
|
||||
$fa-var-moon-o: "\f186";
|
||||
$fa-var-mortar-board: "\f19d";
|
||||
$fa-var-motorcycle: "\f21c";
|
||||
$fa-var-mouse-pointer: "\f245";
|
||||
$fa-var-music: "\f001";
|
||||
$fa-var-navicon: "\f0c9";
|
||||
$fa-var-neuter: "\f22c";
|
||||
$fa-var-newspaper-o: "\f1ea";
|
||||
$fa-var-object-group: "\f247";
|
||||
$fa-var-object-ungroup: "\f248";
|
||||
$fa-var-odnoklassniki: "\f263";
|
||||
$fa-var-odnoklassniki-square: "\f264";
|
||||
$fa-var-opencart: "\f23d";
|
||||
$fa-var-openid: "\f19b";
|
||||
$fa-var-opera: "\f26a";
|
||||
$fa-var-optin-monster: "\f23c";
|
||||
$fa-var-outdent: "\f03b";
|
||||
$fa-var-pagelines: "\f18c";
|
||||
$fa-var-paint-brush: "\f1fc";
|
||||
|
|
@ -353,19 +498,24 @@ $fa-var-paperclip: "\f0c6";
|
|||
$fa-var-paragraph: "\f1dd";
|
||||
$fa-var-paste: "\f0ea";
|
||||
$fa-var-pause: "\f04c";
|
||||
$fa-var-pause-circle: "\f28b";
|
||||
$fa-var-pause-circle-o: "\f28c";
|
||||
$fa-var-paw: "\f1b0";
|
||||
$fa-var-paypal: "\f1ed";
|
||||
$fa-var-pencil: "\f040";
|
||||
$fa-var-pencil-square: "\f14b";
|
||||
$fa-var-pencil-square-o: "\f044";
|
||||
$fa-var-percent: "\f295";
|
||||
$fa-var-phone: "\f095";
|
||||
$fa-var-phone-square: "\f098";
|
||||
$fa-var-photo: "\f03e";
|
||||
$fa-var-picture-o: "\f03e";
|
||||
$fa-var-pie-chart: "\f200";
|
||||
$fa-var-pied-piper: "\f1a7";
|
||||
$fa-var-pied-piper: "\f2ae";
|
||||
$fa-var-pied-piper-alt: "\f1a8";
|
||||
$fa-var-pied-piper-pp: "\f1a7";
|
||||
$fa-var-pinterest: "\f0d2";
|
||||
$fa-var-pinterest-p: "\f231";
|
||||
$fa-var-pinterest-square: "\f0d3";
|
||||
$fa-var-plane: "\f072";
|
||||
$fa-var-play: "\f04b";
|
||||
|
|
@ -376,28 +526,36 @@ $fa-var-plus: "\f067";
|
|||
$fa-var-plus-circle: "\f055";
|
||||
$fa-var-plus-square: "\f0fe";
|
||||
$fa-var-plus-square-o: "\f196";
|
||||
$fa-var-podcast: "\f2ce";
|
||||
$fa-var-power-off: "\f011";
|
||||
$fa-var-print: "\f02f";
|
||||
$fa-var-product-hunt: "\f288";
|
||||
$fa-var-puzzle-piece: "\f12e";
|
||||
$fa-var-qq: "\f1d6";
|
||||
$fa-var-qrcode: "\f029";
|
||||
$fa-var-question: "\f128";
|
||||
$fa-var-question-circle: "\f059";
|
||||
$fa-var-question-circle-o: "\f29c";
|
||||
$fa-var-quora: "\f2c4";
|
||||
$fa-var-quote-left: "\f10d";
|
||||
$fa-var-quote-right: "\f10e";
|
||||
$fa-var-ra: "\f1d0";
|
||||
$fa-var-random: "\f074";
|
||||
$fa-var-ravelry: "\f2d9";
|
||||
$fa-var-rebel: "\f1d0";
|
||||
$fa-var-recycle: "\f1b8";
|
||||
$fa-var-reddit: "\f1a1";
|
||||
$fa-var-reddit-alien: "\f281";
|
||||
$fa-var-reddit-square: "\f1a2";
|
||||
$fa-var-refresh: "\f021";
|
||||
$fa-var-registered: "\f25d";
|
||||
$fa-var-remove: "\f00d";
|
||||
$fa-var-renren: "\f18b";
|
||||
$fa-var-reorder: "\f0c9";
|
||||
$fa-var-repeat: "\f01e";
|
||||
$fa-var-reply: "\f112";
|
||||
$fa-var-reply-all: "\f122";
|
||||
$fa-var-resistance: "\f1d0";
|
||||
$fa-var-retweet: "\f079";
|
||||
$fa-var-rmb: "\f157";
|
||||
$fa-var-road: "\f018";
|
||||
|
|
@ -410,13 +568,18 @@ $fa-var-rss-square: "\f143";
|
|||
$fa-var-rub: "\f158";
|
||||
$fa-var-ruble: "\f158";
|
||||
$fa-var-rupee: "\f156";
|
||||
$fa-var-s15: "\f2cd";
|
||||
$fa-var-safari: "\f267";
|
||||
$fa-var-save: "\f0c7";
|
||||
$fa-var-scissors: "\f0c4";
|
||||
$fa-var-scribd: "\f28a";
|
||||
$fa-var-search: "\f002";
|
||||
$fa-var-search-minus: "\f010";
|
||||
$fa-var-search-plus: "\f00e";
|
||||
$fa-var-sellsy: "\f213";
|
||||
$fa-var-send: "\f1d8";
|
||||
$fa-var-send-o: "\f1d9";
|
||||
$fa-var-server: "\f233";
|
||||
$fa-var-share: "\f064";
|
||||
$fa-var-share-alt: "\f1e0";
|
||||
$fa-var-share-alt-square: "\f1e1";
|
||||
|
|
@ -425,16 +588,29 @@ $fa-var-share-square-o: "\f045";
|
|||
$fa-var-shekel: "\f20b";
|
||||
$fa-var-sheqel: "\f20b";
|
||||
$fa-var-shield: "\f132";
|
||||
$fa-var-ship: "\f21a";
|
||||
$fa-var-shirtsinbulk: "\f214";
|
||||
$fa-var-shopping-bag: "\f290";
|
||||
$fa-var-shopping-basket: "\f291";
|
||||
$fa-var-shopping-cart: "\f07a";
|
||||
$fa-var-shower: "\f2cc";
|
||||
$fa-var-sign-in: "\f090";
|
||||
$fa-var-sign-language: "\f2a7";
|
||||
$fa-var-sign-out: "\f08b";
|
||||
$fa-var-signal: "\f012";
|
||||
$fa-var-signing: "\f2a7";
|
||||
$fa-var-simplybuilt: "\f215";
|
||||
$fa-var-sitemap: "\f0e8";
|
||||
$fa-var-skyatlas: "\f216";
|
||||
$fa-var-skype: "\f17e";
|
||||
$fa-var-slack: "\f198";
|
||||
$fa-var-sliders: "\f1de";
|
||||
$fa-var-slideshare: "\f1e7";
|
||||
$fa-var-smile-o: "\f118";
|
||||
$fa-var-snapchat: "\f2ab";
|
||||
$fa-var-snapchat-ghost: "\f2ac";
|
||||
$fa-var-snapchat-square: "\f2ad";
|
||||
$fa-var-snowflake-o: "\f2dc";
|
||||
$fa-var-soccer-ball-o: "\f1e3";
|
||||
$fa-var-sort: "\f0dc";
|
||||
$fa-var-sort-alpha-asc: "\f15d";
|
||||
|
|
@ -467,13 +643,20 @@ $fa-var-steam-square: "\f1b7";
|
|||
$fa-var-step-backward: "\f048";
|
||||
$fa-var-step-forward: "\f051";
|
||||
$fa-var-stethoscope: "\f0f1";
|
||||
$fa-var-sticky-note: "\f249";
|
||||
$fa-var-sticky-note-o: "\f24a";
|
||||
$fa-var-stop: "\f04d";
|
||||
$fa-var-stop-circle: "\f28d";
|
||||
$fa-var-stop-circle-o: "\f28e";
|
||||
$fa-var-street-view: "\f21d";
|
||||
$fa-var-strikethrough: "\f0cc";
|
||||
$fa-var-stumbleupon: "\f1a4";
|
||||
$fa-var-stumbleupon-circle: "\f1a3";
|
||||
$fa-var-subscript: "\f12c";
|
||||
$fa-var-subway: "\f239";
|
||||
$fa-var-suitcase: "\f0f2";
|
||||
$fa-var-sun-o: "\f185";
|
||||
$fa-var-superpowers: "\f2dd";
|
||||
$fa-var-superscript: "\f12b";
|
||||
$fa-var-support: "\f1cd";
|
||||
$fa-var-table: "\f0ce";
|
||||
|
|
@ -483,6 +666,8 @@ $fa-var-tag: "\f02b";
|
|||
$fa-var-tags: "\f02c";
|
||||
$fa-var-tasks: "\f0ae";
|
||||
$fa-var-taxi: "\f1ba";
|
||||
$fa-var-telegram: "\f2c6";
|
||||
$fa-var-television: "\f26c";
|
||||
$fa-var-tencent-weibo: "\f1d5";
|
||||
$fa-var-terminal: "\f120";
|
||||
$fa-var-text-height: "\f034";
|
||||
|
|
@ -490,6 +675,18 @@ $fa-var-text-width: "\f035";
|
|||
$fa-var-th: "\f00a";
|
||||
$fa-var-th-large: "\f009";
|
||||
$fa-var-th-list: "\f00b";
|
||||
$fa-var-themeisle: "\f2b2";
|
||||
$fa-var-thermometer: "\f2c7";
|
||||
$fa-var-thermometer-0: "\f2cb";
|
||||
$fa-var-thermometer-1: "\f2ca";
|
||||
$fa-var-thermometer-2: "\f2c9";
|
||||
$fa-var-thermometer-3: "\f2c8";
|
||||
$fa-var-thermometer-4: "\f2c7";
|
||||
$fa-var-thermometer-empty: "\f2cb";
|
||||
$fa-var-thermometer-full: "\f2c7";
|
||||
$fa-var-thermometer-half: "\f2c9";
|
||||
$fa-var-thermometer-quarter: "\f2ca";
|
||||
$fa-var-thermometer-three-quarters: "\f2c8";
|
||||
$fa-var-thumb-tack: "\f08d";
|
||||
$fa-var-thumbs-down: "\f165";
|
||||
$fa-var-thumbs-o-down: "\f088";
|
||||
|
|
@ -499,6 +696,8 @@ $fa-var-ticket: "\f145";
|
|||
$fa-var-times: "\f00d";
|
||||
$fa-var-times-circle: "\f057";
|
||||
$fa-var-times-circle-o: "\f05c";
|
||||
$fa-var-times-rectangle: "\f2d3";
|
||||
$fa-var-times-rectangle-o: "\f2d4";
|
||||
$fa-var-tint: "\f043";
|
||||
$fa-var-toggle-down: "\f150";
|
||||
$fa-var-toggle-left: "\f191";
|
||||
|
|
@ -506,10 +705,15 @@ $fa-var-toggle-off: "\f204";
|
|||
$fa-var-toggle-on: "\f205";
|
||||
$fa-var-toggle-right: "\f152";
|
||||
$fa-var-toggle-up: "\f151";
|
||||
$fa-var-trademark: "\f25c";
|
||||
$fa-var-train: "\f238";
|
||||
$fa-var-transgender: "\f224";
|
||||
$fa-var-transgender-alt: "\f225";
|
||||
$fa-var-trash: "\f1f8";
|
||||
$fa-var-trash-o: "\f014";
|
||||
$fa-var-tree: "\f1bb";
|
||||
$fa-var-trello: "\f181";
|
||||
$fa-var-tripadvisor: "\f262";
|
||||
$fa-var-trophy: "\f091";
|
||||
$fa-var-truck: "\f0d1";
|
||||
$fa-var-try: "\f195";
|
||||
|
|
@ -517,26 +721,45 @@ $fa-var-tty: "\f1e4";
|
|||
$fa-var-tumblr: "\f173";
|
||||
$fa-var-tumblr-square: "\f174";
|
||||
$fa-var-turkish-lira: "\f195";
|
||||
$fa-var-tv: "\f26c";
|
||||
$fa-var-twitch: "\f1e8";
|
||||
$fa-var-twitter: "\f099";
|
||||
$fa-var-twitter-square: "\f081";
|
||||
$fa-var-umbrella: "\f0e9";
|
||||
$fa-var-underline: "\f0cd";
|
||||
$fa-var-undo: "\f0e2";
|
||||
$fa-var-universal-access: "\f29a";
|
||||
$fa-var-university: "\f19c";
|
||||
$fa-var-unlink: "\f127";
|
||||
$fa-var-unlock: "\f09c";
|
||||
$fa-var-unlock-alt: "\f13e";
|
||||
$fa-var-unsorted: "\f0dc";
|
||||
$fa-var-upload: "\f093";
|
||||
$fa-var-usb: "\f287";
|
||||
$fa-var-usd: "\f155";
|
||||
$fa-var-user: "\f007";
|
||||
$fa-var-user-circle: "\f2bd";
|
||||
$fa-var-user-circle-o: "\f2be";
|
||||
$fa-var-user-md: "\f0f0";
|
||||
$fa-var-user-o: "\f2c0";
|
||||
$fa-var-user-plus: "\f234";
|
||||
$fa-var-user-secret: "\f21b";
|
||||
$fa-var-user-times: "\f235";
|
||||
$fa-var-users: "\f0c0";
|
||||
$fa-var-vcard: "\f2bb";
|
||||
$fa-var-vcard-o: "\f2bc";
|
||||
$fa-var-venus: "\f221";
|
||||
$fa-var-venus-double: "\f226";
|
||||
$fa-var-venus-mars: "\f228";
|
||||
$fa-var-viacoin: "\f237";
|
||||
$fa-var-viadeo: "\f2a9";
|
||||
$fa-var-viadeo-square: "\f2aa";
|
||||
$fa-var-video-camera: "\f03d";
|
||||
$fa-var-vimeo: "\f27d";
|
||||
$fa-var-vimeo-square: "\f194";
|
||||
$fa-var-vine: "\f1ca";
|
||||
$fa-var-vk: "\f189";
|
||||
$fa-var-volume-control-phone: "\f2a0";
|
||||
$fa-var-volume-down: "\f027";
|
||||
$fa-var-volume-off: "\f026";
|
||||
$fa-var-volume-up: "\f028";
|
||||
|
|
@ -544,17 +767,33 @@ $fa-var-warning: "\f071";
|
|||
$fa-var-wechat: "\f1d7";
|
||||
$fa-var-weibo: "\f18a";
|
||||
$fa-var-weixin: "\f1d7";
|
||||
$fa-var-whatsapp: "\f232";
|
||||
$fa-var-wheelchair: "\f193";
|
||||
$fa-var-wheelchair-alt: "\f29b";
|
||||
$fa-var-wifi: "\f1eb";
|
||||
$fa-var-wikipedia-w: "\f266";
|
||||
$fa-var-window-close: "\f2d3";
|
||||
$fa-var-window-close-o: "\f2d4";
|
||||
$fa-var-window-maximize: "\f2d0";
|
||||
$fa-var-window-minimize: "\f2d1";
|
||||
$fa-var-window-restore: "\f2d2";
|
||||
$fa-var-windows: "\f17a";
|
||||
$fa-var-won: "\f159";
|
||||
$fa-var-wordpress: "\f19a";
|
||||
$fa-var-wpbeginner: "\f297";
|
||||
$fa-var-wpexplorer: "\f2de";
|
||||
$fa-var-wpforms: "\f298";
|
||||
$fa-var-wrench: "\f0ad";
|
||||
$fa-var-xing: "\f168";
|
||||
$fa-var-xing-square: "\f169";
|
||||
$fa-var-y-combinator: "\f23b";
|
||||
$fa-var-y-combinator-square: "\f1d4";
|
||||
$fa-var-yahoo: "\f19e";
|
||||
$fa-var-yc: "\f23b";
|
||||
$fa-var-yc-square: "\f1d4";
|
||||
$fa-var-yelp: "\f1e9";
|
||||
$fa-var-yen: "\f157";
|
||||
$fa-var-yoast: "\f2b1";
|
||||
$fa-var-youtube: "\f167";
|
||||
$fa-var-youtube-play: "\f16a";
|
||||
$fa-var-youtube-square: "\f166";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*!
|
||||
* Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome
|
||||
* Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
|
||||
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
|
||||
*/
|
||||
|
||||
|
|
@ -11,7 +11,8 @@
|
|||
@import "fixed-width";
|
||||
@import "list";
|
||||
@import "bordered-pulled";
|
||||
@import "spinning";
|
||||
@import "animated";
|
||||
@import "rotated-flipped";
|
||||
@import "stacked";
|
||||
@import "icons";
|
||||
@import "screen-reader";
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class Media extends StandardController
|
|||
|
||||
if (!file_put_contents($new_file_path, 'a'))
|
||||
{
|
||||
throw new \Exception('pute de merde');
|
||||
throw new \Exception('Cannot write file ' . $new_file_path);
|
||||
}
|
||||
|
||||
if (!rename($tmpfile_path, $new_file_path))
|
||||
|
|
@ -56,16 +56,6 @@ class Media extends StandardController
|
|||
throw new \Exception('Cannot create file ' . $new_file_path);
|
||||
}
|
||||
|
||||
if (!chown($new_file_path, fileowner($user_path)))
|
||||
{
|
||||
throw new \Exception('Cannot give file ' . $new_file_path . ' to user : ' . fileowner($user_path));
|
||||
}
|
||||
|
||||
if (!chgrp($new_file_path, filegroup($user_path)))
|
||||
{
|
||||
throw new \Exception('Cannot give file ' . $new_file_path . ' to group : ' . filegroup($user_path));
|
||||
}
|
||||
|
||||
if (!chmod($new_file_path, self::DEFAULT_CHMOD))
|
||||
{
|
||||
throw new \Exception('Cannot give file ' . $new_file_path . ' rights : ' . self::DEFAULT_CHMOD);
|
||||
|
|
|
|||
|
|
@ -236,6 +236,19 @@ namespace controllers\internals;
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a phone status.
|
||||
*
|
||||
* @param int $id : Phone id
|
||||
* @param string $status : The new status of the phone
|
||||
*
|
||||
* @return bool : false on error, true on success
|
||||
*/
|
||||
public function update_status(int $id, string $status) : bool
|
||||
{
|
||||
return (bool) $this->get_model()->update($id, ['status' => $status]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the model for the Controller.
|
||||
*/
|
||||
|
|
|
|||
139
controllers/internals/PhoneGroup.php
Normal file
139
controllers/internals/PhoneGroup.php
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of RaspiSMS.
|
||||
*
|
||||
* (c) Pierre-Lin Bonnemaison <plebwebsas@gmail.com>
|
||||
*
|
||||
* This source file is subject to the GPL-3.0 license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace controllers\internals;
|
||||
|
||||
/**
|
||||
* Classe des groups.
|
||||
*/
|
||||
class PhoneGroup extends StandardController
|
||||
{
|
||||
protected $model;
|
||||
|
||||
/**
|
||||
* Create a new phone group for a user.
|
||||
*
|
||||
* @param int $id_user : user id
|
||||
* @param stirng $name : Group name
|
||||
* @param array $phones_ids : Ids of the phones of the group
|
||||
*
|
||||
* @return mixed bool|int : false on error, new group id
|
||||
*/
|
||||
public function create(int $id_user, string $name, array $phones_ids)
|
||||
{
|
||||
$group = [
|
||||
'id_user' => $id_user,
|
||||
'name' => $name,
|
||||
];
|
||||
|
||||
$id_group = $this->get_model()->insert($group);
|
||||
if (!$id_group)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$internal_phone = new Phone($this->bdd);
|
||||
foreach ($phones_ids as $phone_id)
|
||||
{
|
||||
$phone = $internal_phone->get_for_user($id_user, $phone_id);
|
||||
if (!$phone)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->get_model()->insert_phone_group_phone_relation($id_group, $phone_id);
|
||||
}
|
||||
|
||||
$internal_event = new Event($this->bdd);
|
||||
$internal_event->create($id_user, 'PHONE_GROUP_ADD', 'Ajout phone group : ' . $name);
|
||||
|
||||
return $id_group;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a phone group for a user.
|
||||
*
|
||||
* @param int $id_user : User id
|
||||
* @param int $id_group : Group id
|
||||
* @param stirng $name : Group name
|
||||
* @param array $phones_ids : Ids of the phones of the group
|
||||
*
|
||||
* @return bool : False on error, true on success
|
||||
*/
|
||||
public function update_for_user(int $id_user, int $id_group, string $name, array $phones_ids)
|
||||
{
|
||||
$group = [
|
||||
'name' => $name,
|
||||
];
|
||||
|
||||
$result = $this->get_model()->update_for_user($id_user, $id_group, $group);
|
||||
|
||||
$this->get_model()->delete_phone_group_phone_relations($id_group);
|
||||
|
||||
$internal_phone = new Phone($this->bdd);
|
||||
$nb_phone_insert = 0;
|
||||
foreach ($phones_ids as $phone_id)
|
||||
{
|
||||
$phone = $internal_phone->get_for_user($id_user, $phone_id);
|
||||
if (!$phone)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->get_model()->insert_phone_group_phone_relation($id_group, $phone_id))
|
||||
{
|
||||
++$nb_phone_insert;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$result && $nb_phone_insert !== \count($phones_ids))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a group by his name for a user.
|
||||
*
|
||||
* @param int $id_user : User id
|
||||
* @param string $name : Group name
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_by_name_for_user(int $id_user, string $name)
|
||||
{
|
||||
return $this->get_model()->get_by_name_for_user($id_user, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get groups phones.
|
||||
*
|
||||
* @param int $id_group : Group id
|
||||
*
|
||||
* @return array : phones of the group
|
||||
*/
|
||||
public function get_phones($id_group)
|
||||
{
|
||||
return $this->get_model()->get_phones($id_group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the model for the Controller.
|
||||
*/
|
||||
protected function get_model(): \models\PhoneGroup
|
||||
{
|
||||
$this->model = $this->model ?? new \models\PhoneGroup($this->bdd);
|
||||
|
||||
return $this->model;
|
||||
}
|
||||
}
|
||||
|
|
@ -25,8 +25,10 @@ use Monolog\Logger;
|
|||
* @param $at : Scheduled date to send
|
||||
* @param string $text : Text of the message
|
||||
* @param ?int $id_phone : Id of the phone to send message with, null by default
|
||||
* @param ?int $id_phone_group : Id of the phone group to send message with, null by default
|
||||
* @param bool $flash : Is the sms a flash sms, by default false
|
||||
* @param bool $mms : Is the sms a mms, by default false
|
||||
* @param ?string $tag : A string tag to associate to sended SMS
|
||||
* @param array $numbers : Array of numbers to send message to, a number is an array ['number' => '+33XXX', 'data' => '{"key":"value", ...}']
|
||||
* @param array $contacts_ids : Contact ids to send message to
|
||||
* @param array $groups_ids : Group ids to send message to
|
||||
|
|
@ -35,15 +37,17 @@ use Monolog\Logger;
|
|||
*
|
||||
* @return bool : false on error, new id on success
|
||||
*/
|
||||
public function create(int $id_user, $at, string $text, ?int $id_phone = null, bool $flash = false, bool $mms = false, array $numbers = [], array $contacts_ids = [], array $groups_ids = [], array $conditional_group_ids = [], array $media_ids = [])
|
||||
public function create(int $id_user, $at, string $text, ?int $id_phone = null, ?int $id_phone_group = null, bool $flash = false, bool $mms = false, ?string $tag = null, array $numbers = [], array $contacts_ids = [], array $groups_ids = [], array $conditional_group_ids = [], array $media_ids = [])
|
||||
{
|
||||
$scheduled = [
|
||||
'id_user' => $id_user,
|
||||
'at' => $at,
|
||||
'text' => $text,
|
||||
'id_phone' => $id_phone,
|
||||
'id_phone_group' => $id_phone_group,
|
||||
'flash' => $flash,
|
||||
'mms' => $mms,
|
||||
'tag' => $tag,
|
||||
];
|
||||
|
||||
if ('' === $text)
|
||||
|
|
@ -62,6 +66,17 @@ use Monolog\Logger;
|
|||
}
|
||||
}
|
||||
|
||||
if (null !== $id_phone_group)
|
||||
{
|
||||
$internal_phone_group = new PhoneGroup($this->bdd);
|
||||
$find_phone_group = $internal_phone_group->get_for_user($id_user, $id_phone_group);
|
||||
|
||||
if (!$find_phone_group)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//Use transaction to garanty atomicity
|
||||
$this->bdd->beginTransaction();
|
||||
|
||||
|
|
@ -147,8 +162,10 @@ use Monolog\Logger;
|
|||
* @param $at : Scheduled date to send
|
||||
* @param string $text : Text of the message
|
||||
* @param ?int $id_phone : Id of the phone to send message with, null by default
|
||||
* @param ?int $id_phone_group : Id of the phone group to send message with, null by default
|
||||
* @param bool $flash : Is the sms a flash sms, by default false
|
||||
* @param bool $mms : Is the sms a mms, by default false
|
||||
* @param ?string $tag : A string tag to associate to sended SMS
|
||||
* @param array $numbers : Array of numbers to send message to, a number is an array ['number' => '+33XXX', 'data' => '{"key":"value", ...}']
|
||||
* @param array $contacts_ids : Contact ids to send message to
|
||||
* @param array $groups_ids : Group ids to send message to
|
||||
|
|
@ -157,15 +174,17 @@ use Monolog\Logger;
|
|||
*
|
||||
* @return bool : false on error, true on success
|
||||
*/
|
||||
public function update_for_user(int $id_user, int $id_scheduled, $at, string $text, ?string $id_phone = null, bool $flash = false, bool $mms = false, array $numbers = [], array $contacts_ids = [], array $groups_ids = [], array $conditional_group_ids = [], array $media_ids = [])
|
||||
public function update_for_user(int $id_user, int $id_scheduled, $at, string $text, ?int $id_phone = null, ?int $id_phone_group = null, bool $flash = false, bool $mms = false, ?string $tag = null, array $numbers = [], array $contacts_ids = [], array $groups_ids = [], array $conditional_group_ids = [], array $media_ids = [])
|
||||
{
|
||||
$scheduled = [
|
||||
'id_user' => $id_user,
|
||||
'at' => $at,
|
||||
'text' => $text,
|
||||
'id_phone' => $id_phone,
|
||||
'id_phone_group' => $id_phone_group,
|
||||
'mms' => $mms,
|
||||
'flash' => $flash,
|
||||
'tag' => $tag,
|
||||
];
|
||||
|
||||
if (null !== $id_phone)
|
||||
|
|
@ -179,6 +198,17 @@ use Monolog\Logger;
|
|||
}
|
||||
}
|
||||
|
||||
if (null !== $id_phone_group)
|
||||
{
|
||||
$internal_phone_group = new PhoneGroup($this->bdd);
|
||||
$find_phone_group = $internal_phone_group->get_for_user($id_user, $id_phone_group);
|
||||
|
||||
if (!$find_phone_group)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//Ensure atomicity
|
||||
$this->bdd->beginTransaction();
|
||||
|
||||
|
|
@ -413,13 +443,14 @@ use Monolog\Logger;
|
|||
$internal_group = new \controllers\internals\Group($this->bdd);
|
||||
$internal_conditional_group = new \controllers\internals\ConditionalGroup($this->bdd);
|
||||
$internal_phone = new \controllers\internals\Phone($this->bdd);
|
||||
$internal_phone_group = new \controllers\internals\PhoneGroup($this->bdd);
|
||||
$internal_smsstop = new \controllers\internals\SmsStop($this->bdd);
|
||||
$internal_sended = new \controllers\internals\Sended($this->bdd);
|
||||
|
||||
$users_smsstops = [];
|
||||
$users_settings = [];
|
||||
$users_phones = [];
|
||||
$users_mms_phones = [];
|
||||
$users_phone_groups = [];
|
||||
|
||||
$now = new \DateTime();
|
||||
$now = $now->format('Y-m-d H:i:s');
|
||||
|
|
@ -457,7 +488,6 @@ use Monolog\Logger;
|
|||
if (!isset($users_phones[$id_user]))
|
||||
{
|
||||
$users_phones[$id_user] = [];
|
||||
$users_mms_phones[$id_user] = [];
|
||||
|
||||
$phones = $internal_phone->gets_for_user($id_user);
|
||||
foreach ($phones as &$phone)
|
||||
|
|
@ -475,26 +505,26 @@ use Monolog\Logger;
|
|||
$phone['remaining_volume'] = $remaining_volume;
|
||||
$users_phones[$id_user][$phone['id']] = $phone;
|
||||
}
|
||||
}
|
||||
|
||||
$mms_phones = $internal_phone->gets_phone_supporting_mms_for_user($id_user, $internal_phone::MMS_SENDING);
|
||||
foreach ($mms_phones as &$mms_phone)
|
||||
if (!isset($users_phone_groups[$id_user]))
|
||||
{
|
||||
$limits = $internal_phone->get_limits($mms_phone['id']);
|
||||
$users_phone_groups[$id_user] = [];
|
||||
|
||||
$remaining_volume = PHP_INT_MAX;
|
||||
foreach ($limits as $limit)
|
||||
$phone_groups = $internal_phone_group->gets_for_user($id_user);
|
||||
foreach ($phone_groups as $phone_group)
|
||||
{
|
||||
$startpoint = new \DateTime($limit['startpoint']);
|
||||
$consumed = $internal_sended->count_since_for_phone_and_user($id_user, $mms_phone['id'], $startpoint);
|
||||
$remaining_volume = min(($limit['volume'] - $consumed), $remaining_volume);
|
||||
$phones = $internal_phone_group->get_phones($phone_group['id']);
|
||||
$phone_group['phones'] = [];
|
||||
foreach ($phones as $phone)
|
||||
{
|
||||
$phone_group['phones'][] = $phone['id'];
|
||||
}
|
||||
|
||||
$mms_phone['remaining_volume'] = $remaining_volume;
|
||||
$users_mms_phones[$id_user][$mms_phone['id']] = $mms_phone;
|
||||
$users_phone_groups[$id_user][$phone_group['id']] = $phone_group;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Add medias to mms
|
||||
$scheduled['medias'] = [];
|
||||
if ($scheduled['mms'])
|
||||
|
|
@ -509,6 +539,12 @@ use Monolog\Logger;
|
|||
$phone_to_use = $users_phones[$id_user][$scheduled['id_phone']] ?? null;
|
||||
}
|
||||
|
||||
$phone_group_to_use = null;
|
||||
if ($scheduled['id_phone_group'])
|
||||
{
|
||||
$phone_group_to_use = $users_phone_groups[$id_user][$scheduled['id_phone_group']] ?? null;
|
||||
}
|
||||
|
||||
|
||||
// We turn all contacts, groups and conditional groups into just contacts
|
||||
$contacts = $this->get_contacts($id_scheduled);
|
||||
|
|
@ -620,16 +656,41 @@ use Monolog\Logger;
|
|||
if (null === $phone_to_use)
|
||||
{
|
||||
$phones_subset = $users_phones[$id_user];
|
||||
if ($scheduled['mms'])
|
||||
|
||||
if ($phone_group_to_use)
|
||||
{
|
||||
$phones_subset = $users_mms_phones[$id_user] ?: $phones_subset;
|
||||
$phones_subset = array_filter($phones_subset, function ($phone) use ($phone_group_to_use) {
|
||||
return in_array($phone['id'], $phone_group_to_use['phones']);
|
||||
});
|
||||
}
|
||||
|
||||
if ($scheduled['mms'])
|
||||
{
|
||||
$mms_only = array_filter($phones_subset, function ($phone) {
|
||||
return $phone['adapter']::meta_support_mms_sending();
|
||||
});
|
||||
|
||||
$phones_subset = $mms_only ?: $phones_subset;
|
||||
}
|
||||
|
||||
// Keep only available phones
|
||||
$remaining_volume_phones = array_filter($phones_subset, function ($phone) {
|
||||
return $phone['status'] == \models\Phone::STATUS_AVAILABLE;
|
||||
});
|
||||
$phones_subset = $remaining_volume_phones ?: $phones_subset;
|
||||
|
||||
|
||||
// Keep only phones with remaining volume
|
||||
if ((int) ($users_settings[$id_user]['phone_limit'] ?? false))
|
||||
{
|
||||
$remaining_volume_phones = array_filter($phones_subset, function ($phone) {
|
||||
return $phone['remaining_volume'] > 0;
|
||||
});
|
||||
$phones_subset = $remaining_volume_phones ?: $phones_subset;
|
||||
}
|
||||
|
||||
if ((int) ($users_settings[$id_user]['phone_priority'] ?? false))
|
||||
{
|
||||
$max_priority_phones = [];
|
||||
$max_priority = PHP_INT_MIN;
|
||||
foreach ($phones_subset as $phone)
|
||||
|
|
@ -650,6 +711,8 @@ use Monolog\Logger;
|
|||
}
|
||||
|
||||
$phones_subset = $max_priority_phones;
|
||||
}
|
||||
|
||||
if ($phones_subset)
|
||||
{
|
||||
$random_phone = $phones_subset[array_rand($phones_subset)];
|
||||
|
|
@ -670,16 +733,13 @@ use Monolog\Logger;
|
|||
'destination' => $target['number'],
|
||||
'flash' => $scheduled['flash'],
|
||||
'mms' => $scheduled['mms'],
|
||||
'tag' => $scheduled['tag'],
|
||||
'medias' => $scheduled['medias'],
|
||||
'text' => $text,
|
||||
];
|
||||
|
||||
// Consume one sms from remaining volume of phone, dont forget to do the same for the entry in mms phones
|
||||
// Consume one sms from remaining volume of phone
|
||||
$users_phones[$id_user][$id_phone]['remaining_volume'] --;
|
||||
if ($users_mms_phones[$id_user][$id_phone] ?? false)
|
||||
{
|
||||
$users_mms_phones[$id_user][$id_phone] --;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
namespace controllers\internals;
|
||||
|
||||
use Exception;
|
||||
|
||||
class Sended extends StandardController
|
||||
{
|
||||
protected $model;
|
||||
|
|
@ -44,13 +46,14 @@ namespace controllers\internals;
|
|||
* @param string $adapter : Name of the adapter service used to send the message
|
||||
* @param bool $flash : Is the sms a flash
|
||||
* @param bool $mms : Is the sms a MMS. By default false.
|
||||
* @param ?string $tag : A string tag to associate to sended SMS
|
||||
* @param array $medias : Array of medias to link to the MMS
|
||||
* @param ?int $originating_scheduled : Id of the scheduled message that was responsible for sending this message. By default null.
|
||||
* @param string $status : Status of a the sms. By default \models\Sended::STATUS_UNKNOWN
|
||||
*
|
||||
* @return mixed : false on error, new sended id else
|
||||
*/
|
||||
public function create(int $id_user, int $id_phone, $at, string $text, string $destination, string $uid, string $adapter, bool $flash = false, bool $mms = false, array $medias = [], ?int $originating_scheduled = null, ?string $status = \models\Sended::STATUS_UNKNOWN)
|
||||
public function create(int $id_user, int $id_phone, $at, string $text, string $destination, string $uid, string $adapter, bool $flash = false, bool $mms = false, ?string $tag = null, array $medias = [], ?int $originating_scheduled = null, ?string $status = \models\Sended::STATUS_UNKNOWN)
|
||||
{
|
||||
$sended = [
|
||||
'id_user' => $id_user,
|
||||
|
|
@ -62,6 +65,7 @@ namespace controllers\internals;
|
|||
'adapter' => $adapter,
|
||||
'flash' => $flash,
|
||||
'mms' => $mms,
|
||||
'tag' => $tag,
|
||||
'status' => $status,
|
||||
'originating_scheduled' => $originating_scheduled,
|
||||
];
|
||||
|
|
@ -184,13 +188,15 @@ namespace controllers\internals;
|
|||
*
|
||||
* @param int $id_user : User id
|
||||
* @param int $id_phone : Phone id we want the number of sended message for
|
||||
* @param \DateTime $since : Date since which we want sended number
|
||||
* @param ?\DateTime $since : Date since which we want sended number. Default to null.
|
||||
* @param ?\DateTime $before : Date up to which we want sended number. Default to null.
|
||||
* @param ?string $tag_like : Tag to filter sms by, this is not a = but a LIKE operator
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count_since_for_phone_and_user(int $id_user, int $id_phone, \DateTime $since): int
|
||||
public function count_since_for_phone_and_user(int $id_user, int $id_phone, ?\DateTime $since, ?\DateTime $before = null, ?string $tag_like = null): int
|
||||
{
|
||||
return $this->get_model()->count_since_for_phone_and_user($id_user, $id_phone, $since);
|
||||
return $this->get_model()->count_since_for_phone_and_user($id_user, $id_phone, $since, $before, $tag_like);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -236,6 +242,7 @@ namespace controllers\internals;
|
|||
* @param $text : Text of the message
|
||||
* @param string $destination : Number of the receiver
|
||||
* @param bool $flash : Is the sms a flash. By default false.
|
||||
* @param ?string $tag : A string tag to associate to sended SMS
|
||||
* @param bool $mms : Is the sms a MMS. By default false.
|
||||
* @param array $medias : Array of medias to link to the MMS
|
||||
* @param string $status : Status of a the sms. By default \models\Sended::STATUS_UNKNOWN
|
||||
|
|
@ -246,13 +253,16 @@ namespace controllers\internals;
|
|||
* ?string 'error_message' => null if success, error message else
|
||||
* ]
|
||||
*/
|
||||
public function send(\adapters\AdapterInterface $adapter, int $id_user, int $id_phone, string $text, string $destination, bool $flash = false, bool $mms = false, array $medias = [], $originating_scheduled = null, string $status = \models\Sended::STATUS_UNKNOWN): array
|
||||
public function send(\adapters\AdapterInterface $adapter, int $id_user, int $id_phone, string $text, string $destination, bool $flash = false, bool $mms = false, ?string $tag = null, array $medias = [], $originating_scheduled = null, string $status = \models\Sended::STATUS_UNKNOWN): array
|
||||
{
|
||||
$return = [
|
||||
'error' => false,
|
||||
'error_message' => null,
|
||||
];
|
||||
|
||||
$internal_setting = new Setting();
|
||||
$user_settings = $internal_setting->gets_for_user($id_user);
|
||||
|
||||
$at = (new \DateTime())->format('Y-m-d H:i:s');
|
||||
$media_uris = [];
|
||||
foreach ($medias as $media)
|
||||
|
|
@ -275,54 +285,69 @@ namespace controllers\internals;
|
|||
$text .= "\n" . join(' - ', $media_urls);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
//If we reached our max quota, do not send the message
|
||||
$internal_quota = new Quota($this->bdd);
|
||||
$nb_credits = $internal_quota::compute_credits_for_message($text); //Calculate how much credit the message require
|
||||
if (!$internal_quota->has_enough_credit($id_user, $nb_credits))
|
||||
{
|
||||
$return['error'] = true;
|
||||
$return['error_message'] = 'Not enough credit to send message.';
|
||||
throw new Exception('Not enough credit to send message.');
|
||||
}
|
||||
|
||||
//If we reached limit for this phone, do not send the message
|
||||
// If this phone status indicate it is not available
|
||||
$internal_phone = new Phone($this->bdd);
|
||||
$internal_sended = new Sended($this->bdd);
|
||||
$phone = $internal_phone->get_for_user($id_user, $id_phone);
|
||||
if (!$phone || $phone['status'] != \models\Phone::STATUS_AVAILABLE)
|
||||
{
|
||||
throw new Exception('Invalid phone status : ' . $phone['status']);
|
||||
}
|
||||
|
||||
//If we reached limit for this phone and phone limits are enabled, do not send the message
|
||||
if ((int) ($user_settings['phone_limit'] ?? false))
|
||||
{
|
||||
$limits = $internal_phone->get_limits($id_phone);
|
||||
|
||||
$remaining_volume = PHP_INT_MAX;
|
||||
foreach ($limits as $limit)
|
||||
{
|
||||
$startpoint = new \DateTime($limit['startpoint']);
|
||||
$consumed = $internal_sended->count_since_for_phone_and_user($id_user, $id_phone, $startpoint);
|
||||
$consumed = $this->count_since_for_phone_and_user($id_user, $id_phone, $startpoint);
|
||||
$remaining_volume = min(($limit['volume'] - $consumed), $remaining_volume);
|
||||
}
|
||||
|
||||
if ($remaining_volume < 1)
|
||||
{
|
||||
$return['error'] = true;
|
||||
$return['error_message'] = 'Phone send limit have been reached.';
|
||||
throw new Exception('Phone send limit have been reached.');
|
||||
}
|
||||
}
|
||||
|
||||
$uid = uniqid();
|
||||
if (!$return['error'])
|
||||
{
|
||||
$response = $adapter->send($destination, $text, $flash, $mms, $media_uris);
|
||||
$uid = $response['uid'] ?? $uid;
|
||||
|
||||
if ($response['error'])
|
||||
{
|
||||
$return['error'] = true;
|
||||
$return['error_message'] = $response['error_message'];
|
||||
}
|
||||
else // If send with success, consume credit
|
||||
{
|
||||
$internal_quota->consume_credit($id_user, $nb_credits);
|
||||
}
|
||||
throw new Exception($response['error_message']);
|
||||
}
|
||||
|
||||
// If we fail to send or not, we will always save message as sended, only the status will change.
|
||||
$status = $return['error'] ? \models\Sended::STATUS_FAILED : \models\Sended::STATUS_UNKNOWN;
|
||||
$sended_id = $this->create($id_user, $id_phone, $at, $text, $destination, $uid, $adapter->meta_classname(), $flash, $mms, $medias, $originating_scheduled, $status);
|
||||
$uid = $response['uid'];
|
||||
$status = \models\Sended::STATUS_UNKNOWN;
|
||||
|
||||
// If send with success, consume credit
|
||||
$internal_quota->consume_credit($id_user, $nb_credits);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$return['error'] = true;
|
||||
$return['error_message'] = $e->getMessage();
|
||||
|
||||
$status = \models\Sended::STATUS_FAILED;
|
||||
|
||||
return $return;
|
||||
}
|
||||
finally
|
||||
{
|
||||
$uid = $uid ?? uniqid();
|
||||
$sended_id = $this->create($id_user, $id_phone, $at, $text, $destination, $uid, $adapter->meta_classname(), $flash, $mms, $tag, $medias, $originating_scheduled, $status);
|
||||
|
||||
$webhook_body = [
|
||||
'id' => $sended_id,
|
||||
|
|
@ -341,6 +366,7 @@ namespace controllers\internals;
|
|||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the model for the Controller.
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ namespace controllers\publics;
|
|||
|
||||
private $internal_user;
|
||||
private $internal_phone;
|
||||
private $internal_phone_group;
|
||||
private $internal_received;
|
||||
private $internal_sended;
|
||||
private $internal_scheduled;
|
||||
|
|
@ -72,6 +73,7 @@ namespace controllers\publics;
|
|||
$bdd = \descartes\Model::_connect(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD);
|
||||
$this->internal_user = new \controllers\internals\User($bdd);
|
||||
$this->internal_phone = new \controllers\internals\Phone($bdd);
|
||||
$this->internal_phone_group = new \controllers\internals\PhoneGroup($bdd);
|
||||
$this->internal_received = new \controllers\internals\Received($bdd);
|
||||
$this->internal_sended = new \controllers\internals\Sended($bdd);
|
||||
$this->internal_scheduled = new \controllers\internals\Scheduled($bdd);
|
||||
|
|
@ -118,14 +120,14 @@ namespace controllers\publics;
|
|||
/**
|
||||
* List all entries of a certain type for the current user, sorted by id.
|
||||
*
|
||||
* @param string $entry_type : Type of entries we want to list ['sended', 'received', 'scheduled', 'contact', 'group', 'conditional_group', 'phone', 'media']
|
||||
* @param string $entry_type : Type of entries we want to list ['sended', 'received', 'scheduled', 'contact', 'group', 'conditional_group', 'phone', 'phone_group', 'media']
|
||||
* @param int $page : Pagination number, Default = 0. Group of 25 results.
|
||||
*
|
||||
* @return : List of entries
|
||||
*/
|
||||
public function get_entries(string $entry_type, int $page = 0)
|
||||
{
|
||||
$entry_types = ['sended', 'received', 'scheduled', 'contact', 'group', 'conditional_group', 'phone', 'media'];
|
||||
$entry_types = ['sended', 'received', 'scheduled', 'contact', 'group', 'conditional_group', 'phone', 'phone_group', 'media'];
|
||||
|
||||
if (!\in_array($entry_type, $entry_types, true))
|
||||
{
|
||||
|
|
@ -191,6 +193,26 @@ namespace controllers\publics;
|
|||
unset($entries[$key]['adapter_data']);
|
||||
}
|
||||
}
|
||||
// Special case for phone group we must add phones because its a join
|
||||
elseif ('phone_group' === $entry_type)
|
||||
{
|
||||
foreach ($entries as $key => $entry)
|
||||
{
|
||||
$phones = $this->internal_phone_group->get_phones($entry['id']);
|
||||
// Hide meta data of phones if needed
|
||||
foreach ($phones as &$phone)
|
||||
{
|
||||
if (!$phone['adapter']::meta_hide_data())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
unset($phone['adapter_data']);
|
||||
}
|
||||
|
||||
$entries[$key]['phones'] = $phones;
|
||||
}
|
||||
}
|
||||
|
||||
$return = self::DEFAULT_RETURN;
|
||||
$return['response'] = $entries;
|
||||
|
|
@ -210,14 +232,84 @@ namespace controllers\publics;
|
|||
return $this->json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return info about volume of sms sended for a period
|
||||
*
|
||||
* @param ?string $_POST['start'] : Date from which to get sms volume, format Y-m-d H:i:s. Default to null.
|
||||
* @param ?string $_POST['end'] : Date up to which to get sms volume, format Y-m-d H:i:s. Default to null.
|
||||
* @param ?string $_POST['tag'] : Tag to filter SMS by. If set, only sended sms with a matching tag will be counted. Default to null.
|
||||
*
|
||||
* @return : List of entries
|
||||
*/
|
||||
public function get_usage()
|
||||
{
|
||||
$start = $_GET['start'] ?? null;
|
||||
$end = $_GET['end'] ?? null;
|
||||
$tag = $_GET['tag'] ?? null;
|
||||
|
||||
$return = self::DEFAULT_RETURN;
|
||||
|
||||
if ($start)
|
||||
{
|
||||
if (!\controllers\internals\Tool::validate_date($start, 'Y-m-d H:i:s'))
|
||||
{
|
||||
$return = self::DEFAULT_RETURN;
|
||||
$return['error'] = self::ERROR_CODES['INVALID_PARAMETER'];
|
||||
$return['message'] = self::ERROR_MESSAGES['INVALID_PARAMETER'] . 'start must be a date of format "Y-m-d H:i:s".';
|
||||
$this->auto_http_code(false);
|
||||
|
||||
return $this->json($return);
|
||||
}
|
||||
|
||||
$start = new \DateTime($start);
|
||||
}
|
||||
|
||||
if ($end)
|
||||
{
|
||||
if (!\controllers\internals\Tool::validate_date($end, 'Y-m-d H:i:s'))
|
||||
{
|
||||
$return = self::DEFAULT_RETURN;
|
||||
$return['error'] = self::ERROR_CODES['INVALID_PARAMETER'];
|
||||
$return['message'] = self::ERROR_MESSAGES['INVALID_PARAMETER'] . 'end must be a date of format "Y-m-d H:i:s".';
|
||||
$this->auto_http_code(false);
|
||||
|
||||
return $this->json($return);
|
||||
}
|
||||
|
||||
$end = new \DateTime($end);
|
||||
}
|
||||
|
||||
$total_sended = 0;
|
||||
$phones_volumes = [];
|
||||
|
||||
$phones = $this->internal_phone->gets_for_user($this->user['id']);
|
||||
foreach ($phones as $phone)
|
||||
{
|
||||
$nb_sended = $this->internal_sended->count_since_for_phone_and_user($this->user['id'], $phone['id'], $start, $end, $tag);
|
||||
$total_sended += $nb_sended;
|
||||
$phones_volumes[$phone['id']] = $nb_sended;
|
||||
}
|
||||
|
||||
$return['response'] = [
|
||||
'total' => $total_sended,
|
||||
'phones_volumes' => $phones_volumes,
|
||||
];
|
||||
|
||||
$this->auto_http_code(true);
|
||||
|
||||
return $this->json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule a message to be send.
|
||||
*
|
||||
* @param string $_POST['at'] : Date to send message at format Y-m-d H:i:s
|
||||
* @param string $_POST['text'] : Text of the message to send
|
||||
* @param string $_POST['id_phone'] : Default null. Id of phone to send the message from. If null use a random phone
|
||||
* @param string $_POST['id_phone'] : Default null. Id of phone to send the message from. If null and id_phone_group null, use a random phone
|
||||
* @param string $_POST['id_phone_group'] : Default null. Id of phone group to send the message from. If null abd id_phone null, use a random phone
|
||||
* @param string $_POST['flash'] : Default false. Is the sms a flash sms.
|
||||
* @param string $_POST['mms'] : Default false. Is the sms a mms.
|
||||
* @param string $_POST['tag'] : Default null. Tag to associate to every sms of the campaign.
|
||||
* @param string $_POST['numbers'] : Array of numbers to send message to
|
||||
* @param string $_POST['contacts'] : Array of ids of contacts to send message to
|
||||
* @param string $_POST['groups'] : Array of ids of groups to send message to
|
||||
|
|
@ -231,8 +323,10 @@ namespace controllers\publics;
|
|||
$at = $_POST['at'] ?? false;
|
||||
$text = $_POST['text'] ?? false;
|
||||
$id_phone = empty($_POST['id_phone']) ? null : $_POST['id_phone'];
|
||||
$id_phone_group = empty($_POST['id_phone_group']) ? null : $_POST['id_phone_group'];
|
||||
$flash = (bool) ($_POST['flash'] ?? false);
|
||||
$mms = (bool) ($_POST['mms'] ?? false);
|
||||
$tag = $_POST['tag'] ?? null;
|
||||
$numbers = $_POST['numbers'] ?? [];
|
||||
$contacts = $_POST['contacts'] ?? [];
|
||||
$groups = $_POST['groups'] ?? [];
|
||||
|
|
@ -417,6 +511,16 @@ namespace controllers\publics;
|
|||
return $this->json($return);
|
||||
}
|
||||
|
||||
if ($id_phone && $id_phone_group)
|
||||
{
|
||||
$return = self::DEFAULT_RETURN;
|
||||
$return['error'] = self::ERROR_CODES['INVALID_PARAMETER'];
|
||||
$return['message'] = self::ERROR_MESSAGES['INVALID_PARAMETER'] . 'id_phone, id_phone_group : You must specify at most one of id_phone or id_phone_group, not both.';
|
||||
$this->auto_http_code(false);
|
||||
|
||||
return $this->json($return);
|
||||
}
|
||||
|
||||
$phone = null;
|
||||
if ($id_phone)
|
||||
{
|
||||
|
|
@ -433,6 +537,22 @@ namespace controllers\publics;
|
|||
return $this->json($return);
|
||||
}
|
||||
|
||||
$phone_group = null;
|
||||
if ($id_phone_group)
|
||||
{
|
||||
$phone_group = $this->internal_phone_group->get_for_user($this->user['id'], $id_phone_group);
|
||||
}
|
||||
|
||||
if ($id_phone_group && !$phone_group)
|
||||
{
|
||||
$return = self::DEFAULT_RETURN;
|
||||
$return['error'] = self::ERROR_CODES['INVALID_PARAMETER'];
|
||||
$return['message'] = self::ERROR_MESSAGES['INVALID_PARAMETER'] . 'id_phone_group : You must specify an id_phone_group number among thoses of user phone groups.';
|
||||
$this->auto_http_code(false);
|
||||
|
||||
return $this->json($return);
|
||||
}
|
||||
|
||||
if ($mms)
|
||||
{
|
||||
foreach ($files_arrays as $file)
|
||||
|
|
@ -455,7 +575,7 @@ namespace controllers\publics;
|
|||
}
|
||||
}
|
||||
|
||||
$scheduled_id = $this->internal_scheduled->create($this->user['id'], $at, $text, $id_phone, $flash, $mms, $numbers, $contacts, $groups, $conditional_groups, $media_ids);
|
||||
$scheduled_id = $this->internal_scheduled->create($this->user['id'], $at, $text, $id_phone, $id_phone_group, $flash, $mms, $tag, $numbers, $contacts, $groups, $conditional_groups, $media_ids);
|
||||
if (!$scheduled_id)
|
||||
{
|
||||
$return = self::DEFAULT_RETURN;
|
||||
|
|
@ -710,7 +830,7 @@ namespace controllers\publics;
|
|||
$priority = $_POST['priority'] ?? $phone['priority'];
|
||||
$priority = max(((int) $priority), 0);
|
||||
$adapter = $_POST['adapter'] ?? $phone['adapter'];
|
||||
$adapter_data = !empty($_POST['adapter_data']) ? $_POST['adapter_data'] : json_decode($phone['adapter_data']);
|
||||
$adapter_data = !empty($_POST['adapter_data']) ? $_POST['adapter_data'] : json_decode($phone['adapter_data'], true);
|
||||
$adapter_data = is_array($adapter_data) ? $adapter_data : [$adapter_data];
|
||||
$limits = $_POST['limits'] ?? $limits;
|
||||
$limits = is_array($limits) ? $limits : [$limits];
|
||||
|
|
@ -890,4 +1010,35 @@ namespace controllers\publics;
|
|||
|
||||
return $this->json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger re-checking of a phone status
|
||||
*
|
||||
* @param int $id : Id of phone to re-check status
|
||||
*/
|
||||
public function post_update_phone_status ($id)
|
||||
{
|
||||
$return = self::DEFAULT_RETURN;
|
||||
|
||||
$phone = $this->internal_phone->get_for_user($this->user['id'], $id);
|
||||
if (!$phone)
|
||||
{
|
||||
$return['error'] = self::ERROR_CODES['CANNOT_UPDATE'];
|
||||
$return['message'] = self::ERROR_MESSAGES['CANNOT_UPDATE'];
|
||||
$this->auto_http_code(false);
|
||||
|
||||
return $this->json($return);
|
||||
}
|
||||
|
||||
//Check adapter is working correctly with thoses names and data
|
||||
$adapter_classname = $phone['adapter'];
|
||||
$adapter_instance = new $adapter_classname($phone['adapter_data']);
|
||||
$new_status = $adapter_instance->check_phone_status();
|
||||
|
||||
$status_update = $this->internal_phone->update_status($id, $new_status);
|
||||
$return['response'] = $new_status;
|
||||
$this->auto_http_code(true);
|
||||
|
||||
return $this->json($return);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -234,6 +234,7 @@ namespace controllers\publics;
|
|||
$at = $now;
|
||||
$text = $_POST['text'] ?? '';
|
||||
$destination = $_POST['destination'] ?? false;
|
||||
$tag = $_POST['tag'] ?? null;
|
||||
$id_phone = $_POST['id_phone'] ?? false;
|
||||
$files = $_FILES['medias'] ?? false;
|
||||
|
||||
|
|
@ -315,7 +316,7 @@ namespace controllers\publics;
|
|||
//Destinations must be an array of number
|
||||
$destinations = [['number' => $destination, 'data' => '[]']];
|
||||
|
||||
if (!$this->internal_scheduled->create($id_user, $at, $text, $id_phone, false, $mms, $destinations, [], [], [], $media_ids))
|
||||
if (!$this->internal_scheduled->create($id_user, $at, $text, $id_phone, null, false, $mms, $tag, $destinations, [], [], [], $media_ids))
|
||||
{
|
||||
$return['success'] = false;
|
||||
$return['message'] = 'Impossible de créer le Sms';
|
||||
|
|
|
|||
|
|
@ -88,6 +88,11 @@ class Phone extends \descartes\Controller
|
|||
{
|
||||
$phone['callback_end_call'] = \descartes\Router::url('Callback', 'end_call', ['id_phone' => $phone['id']], ['api_key' => $api_key]);
|
||||
}
|
||||
|
||||
if ($adapter['meta_support_phone_status'])
|
||||
{
|
||||
$phone['support_phone_status'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
|
@ -425,7 +430,14 @@ class Phone extends \descartes\Controller
|
|||
continue;
|
||||
}
|
||||
|
||||
if ($find_adapter['meta_hidden'])
|
||||
$current_phone = $this->internal_phone->get_for_user($id_user, $id_phone);
|
||||
if (!$current_phone)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// We can only use an hidden adapter if it was already the adapter we was using
|
||||
if ($find_adapter['meta_hidden'] && $adapter != $current_phone['adapter'])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -499,4 +511,53 @@ class Phone extends \descartes\Controller
|
|||
|
||||
return $this->redirect(\descartes\Router::url('Phone', 'list'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Re-check phone status
|
||||
* @param array int $_GET['ids'] : ids of phones we want to update status
|
||||
* @param $csrf : CSRF token
|
||||
*/
|
||||
public function update_status ($csrf)
|
||||
{
|
||||
if (!$this->verify_csrf($csrf))
|
||||
{
|
||||
\FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !');
|
||||
|
||||
return $this->redirect(\descartes\Router::url('Phone', 'add'));
|
||||
}
|
||||
|
||||
$ids = $_GET['ids'] ?? [];
|
||||
$id_user = $_SESSION['user']['id'];
|
||||
|
||||
foreach ($ids as $id)
|
||||
{
|
||||
$phone = $this->internal_phone->get_for_user($id_user, $id);
|
||||
|
||||
//Check adapter is working correctly with thoses names and data
|
||||
$adapter_classname = $phone['adapter'];
|
||||
if (!call_user_func([$adapter_classname, 'meta_support_phone_status']))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$adapter_instance = new $adapter_classname($phone['adapter_data']);
|
||||
$new_status = $adapter_instance->check_phone_status();
|
||||
|
||||
$status_update = $this->internal_phone->update_status($id, $new_status);
|
||||
}
|
||||
|
||||
\FlashMessage\FlashMessage::push('success', 'Les status des téléphones ont bien été mis à jour.');
|
||||
|
||||
return $this->redirect(\descartes\Router::url('Phone', 'list'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of phones as a JSON array
|
||||
*/
|
||||
public function json_list()
|
||||
{
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($this->internal_phone->list_for_user($_SESSION['user']['id']));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
245
controllers/publics/PhoneGroup.php
Normal file
245
controllers/publics/PhoneGroup.php
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of RaspiSMS.
|
||||
*
|
||||
* (c) Pierre-Lin Bonnemaison <plebwebsas@gmail.com>
|
||||
*
|
||||
* This source file is subject to the GPL-3.0 license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace controllers\publics;
|
||||
|
||||
/**
|
||||
* Page of phone groups.
|
||||
*/
|
||||
class PhoneGroup extends \descartes\Controller
|
||||
{
|
||||
private $internal_phone_group;
|
||||
private $internal_phone;
|
||||
private $internal_event;
|
||||
|
||||
/**
|
||||
* Call before any other func to check user is connected
|
||||
*
|
||||
* @return void;
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$bdd = \descartes\Model::_connect(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD);
|
||||
|
||||
$this->internal_phone_group = new \controllers\internals\PhoneGroup($bdd);
|
||||
$this->internal_phone = new \controllers\internals\Phone($bdd);
|
||||
$this->internal_event = new \controllers\internals\Event($bdd);
|
||||
|
||||
\controllers\internals\Tool::verifyconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all groups as an array for administration.
|
||||
*/
|
||||
public function list()
|
||||
{
|
||||
$this->render('phone_group/list');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return groups as json.
|
||||
*/
|
||||
public function list_json()
|
||||
{
|
||||
$entities = $this->internal_phone_group->list_for_user($_SESSION['user']['id']);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['data' => $entities]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a list of phone groups
|
||||
*
|
||||
* @param array int $_GET['ids'] : Ids of phone groups to delete
|
||||
* @param mixed $csrf
|
||||
*
|
||||
* @return boolean;
|
||||
*/
|
||||
public function delete($csrf)
|
||||
{
|
||||
if (!$this->verify_csrf($csrf))
|
||||
{
|
||||
\FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !');
|
||||
|
||||
return $this->redirect(\descartes\Router::url('PhoneGroup', 'list'));
|
||||
}
|
||||
|
||||
$ids = $_GET['ids'] ?? [];
|
||||
foreach ($ids as $id)
|
||||
{
|
||||
$this->internal_phone_group->delete_for_user($_SESSION['user']['id'], $id);
|
||||
}
|
||||
|
||||
return $this->redirect(\descartes\Router::url('PhoneGroup', 'list'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the creation page of a group
|
||||
*/
|
||||
public function add()
|
||||
{
|
||||
$this->render('phone_group/add');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the edition page for phone groups
|
||||
*
|
||||
* @param array $_GET['ids'] : Ids of phone groups to edit
|
||||
*/
|
||||
public function edit()
|
||||
{
|
||||
$ids = $_GET['ids'] ?? [];
|
||||
|
||||
$groups = $this->internal_phone_group->gets_in_for_user($_SESSION['user']['id'], $ids);
|
||||
|
||||
foreach ($groups as $key => $group)
|
||||
{
|
||||
$groups[$key]['phones'] = $this->internal_phone_group->get_phones($group['id']);
|
||||
}
|
||||
|
||||
$this->render('phone_group/edit', [
|
||||
'phone_groups' => $groups,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new phone group
|
||||
*
|
||||
* @param $csrf : CSRF token
|
||||
* @param string $_POST['name'] : Name of phone group
|
||||
* @param array $_POST['phones'] : Ids of phones to put in the group
|
||||
*/
|
||||
public function create($csrf)
|
||||
{
|
||||
if (!$this->verify_csrf($csrf))
|
||||
{
|
||||
\FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !');
|
||||
|
||||
return $this->redirect(\descartes\Router::url('PhoneGroup', 'add'));
|
||||
}
|
||||
|
||||
$name = $_POST['name'] ?? false;
|
||||
$phones_ids = $_POST['phones'] ?? false;
|
||||
|
||||
if (!$name || !$phones_ids)
|
||||
{
|
||||
\FlashMessage\FlashMessage::push('danger', 'Des champs sont manquants !');
|
||||
|
||||
return $this->redirect(\descartes\Router::url('PhoneGroup', 'add'));
|
||||
}
|
||||
|
||||
$id_group = $this->internal_phone_group->create($_SESSION['user']['id'], $name, $phones_ids);
|
||||
if (!$id_group)
|
||||
{
|
||||
\FlashMessage\FlashMessage::push('danger', 'Impossible de créer ce groupe.');
|
||||
|
||||
return $this->redirect(\descartes\Router::url('PhoneGroup', 'add'));
|
||||
}
|
||||
|
||||
\FlashMessage\FlashMessage::push('success', 'Le groupe a bien été créé.');
|
||||
|
||||
return $this->redirect(\descartes\Router::url('PhoneGroup', 'list'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a list of phone groups
|
||||
*
|
||||
* @param $csrf : CSRF token
|
||||
* @param array $_POST['phone_groups'] : An array of phone groups with group id as keys
|
||||
*
|
||||
* @return boolean;
|
||||
*/
|
||||
public function update($csrf)
|
||||
{
|
||||
if (!$this->verify_csrf($csrf))
|
||||
{
|
||||
\FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !');
|
||||
|
||||
return $this->redirect(\descartes\Router::url('PhoneGroup', 'list'));
|
||||
}
|
||||
|
||||
$groups = $_POST['phone_groups'] ?? [];
|
||||
|
||||
$nb_groups_update = 0;
|
||||
foreach ($groups as $id => $group)
|
||||
{
|
||||
foreach ($group['phones_ids'] as $key => $value)
|
||||
{
|
||||
$group['phones_ids'][$key] = (int) $value;
|
||||
}
|
||||
|
||||
$nb_groups_update += (int) $this->internal_phone_group->update_for_user($_SESSION['user']['id'], $id, $group['name'], $group['phones_ids']);
|
||||
}
|
||||
|
||||
if ($nb_groups_update !== \count($groups))
|
||||
{
|
||||
\FlashMessage\FlashMessage::push('danger', 'Certains groupes n\'ont pas pu êtres mis à jour.');
|
||||
|
||||
return $this->redirect(\descartes\Router::url('PhoneGroup', 'list'));
|
||||
}
|
||||
|
||||
\FlashMessage\FlashMessage::push('success', 'Tous les groupes ont été modifiés avec succès.');
|
||||
|
||||
return $this->redirect(\descartes\Router::url('PhoneGroup', 'list'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return phones of a group as json array
|
||||
* @param int $id_group = PhoneGroup id
|
||||
*
|
||||
* @return json
|
||||
*/
|
||||
public function preview (int $id_group)
|
||||
{
|
||||
$return = [
|
||||
'success' => false,
|
||||
'result' => 'Une erreur inconnue est survenue.',
|
||||
];
|
||||
|
||||
$group = $this->internal_phone_group->get_for_user($_SESSION['user']['id'], $id_group);
|
||||
|
||||
if (!$group)
|
||||
{
|
||||
$return['result'] = 'Ce groupe n\'existe pas.';
|
||||
echo json_encode($return);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$phones = $this->internal_phone_group->get_phones($id_group);
|
||||
if (!$phones)
|
||||
{
|
||||
$return['result'] = 'Aucun téléphone dans le groupe.';
|
||||
echo json_encode($return);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($phones as &$phone)
|
||||
{
|
||||
$phone['adapter_name'] = call_user_func([$phone['adapter'], 'meta_name']);
|
||||
}
|
||||
|
||||
$return['success'] = true;
|
||||
$return['result'] = $phones;
|
||||
echo json_encode($return);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cette fonction retourne la liste des groups sous forme JSON.
|
||||
*/
|
||||
public function json_list()
|
||||
{
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($this->internal_phone_group->list_for_user($_SESSION['user']['id']));
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@ namespace controllers\publics;
|
|||
{
|
||||
private $internal_scheduled;
|
||||
private $internal_phone;
|
||||
private $internal_phone_group;
|
||||
private $internal_contact;
|
||||
private $internal_group;
|
||||
private $internal_conditional_group;
|
||||
|
|
@ -34,6 +35,7 @@ namespace controllers\publics;
|
|||
$bdd = \descartes\Model::_connect(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD);
|
||||
$this->internal_scheduled = new \controllers\internals\Scheduled($bdd);
|
||||
$this->internal_phone = new \controllers\internals\Phone($bdd);
|
||||
$this->internal_phone_group = new \controllers\internals\PhoneGroup($bdd);
|
||||
$this->internal_contact = new \controllers\internals\Contact($bdd);
|
||||
$this->internal_group = new \controllers\internals\Group($bdd);
|
||||
$this->internal_conditional_group = new \controllers\internals\ConditionalGroup($bdd);
|
||||
|
|
@ -118,6 +120,7 @@ namespace controllers\publics;
|
|||
|
||||
$contacts = $this->internal_contact->gets_for_user($id_user);
|
||||
$phones = $this->internal_phone->gets_for_user($id_user);
|
||||
$phone_groups = $this->internal_phone_group->gets_for_user($id_user);
|
||||
|
||||
$contact_ids = (isset($_GET['contact_ids']) && \is_array($_GET['contact_ids'])) ? $_GET['contact_ids'] : [];
|
||||
$group_ids = (isset($_GET['group_ids']) && \is_array($_GET['group_ids'])) ? $_GET['group_ids'] : [];
|
||||
|
|
@ -153,6 +156,7 @@ namespace controllers\publics;
|
|||
'now' => $now->format('Y-m-d H:i'),
|
||||
'contacts' => $contacts,
|
||||
'phones' => $phones,
|
||||
'phone_groups' => $phone_groups,
|
||||
'prefilled_contacts' => $prefilled_contacts,
|
||||
'prefilled_groups' => $prefilled_groups,
|
||||
'prefilled_conditional_groups' => $prefilled_conditional_groups,
|
||||
|
|
@ -179,6 +183,7 @@ namespace controllers\publics;
|
|||
|
||||
$all_contacts = $this->internal_contact->gets_for_user($_SESSION['user']['id']);
|
||||
$phones = $this->internal_phone->gets_for_user($_SESSION['user']['id']);
|
||||
$phone_groups = $this->internal_phone_group->gets_for_user($id_user);
|
||||
$scheduleds = $this->internal_scheduled->gets_in_for_user($_SESSION['user']['id'], $ids);
|
||||
|
||||
//Pour chaque message on ajoute les numéros, les contacts & les groups
|
||||
|
|
@ -226,6 +231,7 @@ namespace controllers\publics;
|
|||
$this->render('scheduled/edit', [
|
||||
'scheduleds' => $scheduleds,
|
||||
'phones' => $phones,
|
||||
'phone_groups' => $phone_groups,
|
||||
'contacts' => $all_contacts,
|
||||
]);
|
||||
}
|
||||
|
|
@ -238,7 +244,7 @@ namespace controllers\publics;
|
|||
* @param string $_POST['at'] : Date to send message for
|
||||
* @param string $_POST['text'] : Text of the message
|
||||
* @param ?bool $_POST['flash'] : Is the message a flash message (by default false)
|
||||
* @param ?int $_POST['id_phone'] : Id of the phone to send message from, if null use random phone
|
||||
* @param ?int $_POST['id_phone'] : Id of the phone or phone group to send message from. id will be preceed by phone_ of phonegroup_ depending on type of ressource to use, if null use random phone
|
||||
* @param ?array $_POST['numbers'] : Numbers to send the message to
|
||||
* @param ?array $_POST['contacts'] : Numbers to send the message to
|
||||
* @param ?array $_POST['groups'] : Numbers to send the message to
|
||||
|
|
@ -258,6 +264,7 @@ namespace controllers\publics;
|
|||
$at = $_POST['at'] ?? false;
|
||||
$text = $_POST['text'] ?? false;
|
||||
$flash = (bool) ($_POST['flash'] ?? false);
|
||||
$tag = ($_POST['tag'] ?? null) ?: null;
|
||||
$id_phone = empty($_POST['id_phone']) ? null : $_POST['id_phone'];
|
||||
$numbers = $_POST['numbers'] ?? [];
|
||||
$numbers = is_array($numbers) ? $numbers : [$numbers];
|
||||
|
|
@ -433,7 +440,12 @@ namespace controllers\publics;
|
|||
|
||||
$mms = (bool) count($media_ids);
|
||||
|
||||
$scheduled_id = $this->internal_scheduled->create($id_user, $at, $text, $id_phone, $flash, $mms, $numbers, $contacts, $groups, $conditional_groups, $media_ids);
|
||||
// Check if we must send message to a phone or a phone_group based on if id_phone start with 'phone_' or 'phonegroup_'
|
||||
$original_id_phone = $id_phone;
|
||||
$id_phone = str_starts_with($original_id_phone, 'phone_') ? mb_substr($original_id_phone, mb_strlen('phone_')) : null;
|
||||
$id_phone_group = str_starts_with($original_id_phone, 'phonegroup_') ? mb_substr($original_id_phone, mb_strlen('phonegroup_')) : null;
|
||||
|
||||
$scheduled_id = $this->internal_scheduled->create($id_user, $at, $text, $id_phone, $id_phone_group, $flash, $mms, $tag, $numbers, $contacts, $groups, $conditional_groups, $media_ids);
|
||||
if (!$scheduled_id)
|
||||
{
|
||||
\FlashMessage\FlashMessage::push('danger', 'Impossible de créer le Sms.');
|
||||
|
|
@ -473,6 +485,7 @@ namespace controllers\publics;
|
|||
$text = $scheduled['text'] ?? false;
|
||||
$id_phone = empty($scheduled['id_phone']) ? null : $scheduled['id_phone'];
|
||||
$flash = (bool) ($scheduled['flash'] ?? false);
|
||||
$tag = ($scheduled['tag'] ?? null) ?: null;
|
||||
$numbers = $scheduled['numbers'] ?? [];
|
||||
$contacts = $scheduled['contacts'] ?? [];
|
||||
$groups = $scheduled['groups'] ?? [];
|
||||
|
|
@ -650,7 +663,11 @@ namespace controllers\publics;
|
|||
|
||||
$mms = (bool) count($media_ids);
|
||||
|
||||
$this->internal_scheduled->update_for_user($id_user, $id_scheduled, $at, $text, $id_phone, $flash, $mms, $numbers, $contacts, $groups, $conditional_groups, $media_ids);
|
||||
$original_id_phone = $id_phone;
|
||||
$id_phone = str_starts_with($original_id_phone, 'phone_') ? mb_substr($original_id_phone, mb_strlen('phone_')) : null;
|
||||
$id_phone_group = str_starts_with($original_id_phone, 'phonegroup_') ? mb_substr($original_id_phone, mb_strlen('phonegroup_')) : null;
|
||||
|
||||
$this->internal_scheduled->update_for_user($id_user, $id_scheduled, $at, $text, $id_phone, $id_phone_group, $flash, $mms, $tag, $numbers, $contacts, $groups, $conditional_groups, $media_ids);
|
||||
++$nb_update;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,8 +59,9 @@ namespace controllers\publics;
|
|||
0 => 'phone_name',
|
||||
1 => 'searchable_destination',
|
||||
2 => 'text',
|
||||
3 => 'at',
|
||||
4 => 'status',
|
||||
3 => 'tag',
|
||||
4 => 'at',
|
||||
5 => 'status',
|
||||
];
|
||||
|
||||
$search = $_GET['search']['value'] ?? null;
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ class Phone extends AbstractDaemon
|
|||
//Do message sending
|
||||
$this->logger->info('Try send message : ' . json_encode($message));
|
||||
|
||||
$response = $internal_sended->send($this->adapter, $this->phone['id_user'], $this->phone['id'], $message['text'], $message['destination'], $message['flash'], $message['mms'], $message['medias'], $message['id_scheduled']);
|
||||
$response = $internal_sended->send($this->adapter, $this->phone['id_user'], $this->phone['id'], $message['text'], $message['destination'], $message['flash'], $message['mms'], $message['tag'], $message['medias'], $message['id_scheduled']);
|
||||
if ($response['error'])
|
||||
{
|
||||
$this->logger->error('Failed send message : ' . json_encode($message) . ' with error : ' . $response['error_message']);
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ class Sender extends AbstractDaemon
|
|||
'destination' => $sms['destination'],
|
||||
'flash' => $sms['flash'],
|
||||
'mms' => $sms['mms'],
|
||||
'tag' => $sms['tag'],
|
||||
'medias' => $sms['medias'] ?? [],
|
||||
];
|
||||
|
||||
|
|
|
|||
38
db/migrations/20230218113648_add_status_phone.php
Normal file
38
db/migrations/20230218113648_add_status_phone.php
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
class AddStatusPhone extends AbstractMigration
|
||||
{
|
||||
/**
|
||||
* Change Method.
|
||||
*
|
||||
* Write your reversible migrations using this method.
|
||||
*
|
||||
* More information on writing migrations is available here:
|
||||
* https://book.cakephp.org/phinx/0/en/migrations.html
|
||||
*
|
||||
* The following commands can be used in this method and Phinx will
|
||||
* automatically reverse them when rolling back:
|
||||
*
|
||||
* createTable
|
||||
* renameTable
|
||||
* addColumn
|
||||
* addCustomColumn
|
||||
* renameColumn
|
||||
* addIndex
|
||||
* addForeignKey
|
||||
*
|
||||
* Any other destructive changes will result in an error when trying to
|
||||
* rollback the migration.
|
||||
*
|
||||
* Remember to call "create()" or "update()" and NOT "save()" when working
|
||||
* with the Table class.
|
||||
*/
|
||||
public function change()
|
||||
{
|
||||
$table = $this->table('phone');
|
||||
$table->addColumn('status', 'enum', ['values' => ['available', 'unavailable', 'no_credit'], 'default' => 'available']);
|
||||
$table->update();
|
||||
}
|
||||
}
|
||||
52
db/migrations/20230219014653_create_phone_group.php
Normal file
52
db/migrations/20230219014653_create_phone_group.php
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
use Phinx\Db\Adapter\MysqlAdapter;
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
class CreatePhoneGroup extends AbstractMigration
|
||||
{
|
||||
/**
|
||||
* Change Method.
|
||||
*
|
||||
* Write your reversible migrations using this method.
|
||||
*
|
||||
* More information on writing migrations is available here:
|
||||
* https://book.cakephp.org/phinx/0/en/migrations.html
|
||||
*
|
||||
* The following commands can be used in this method and Phinx will
|
||||
* automatically reverse them when rolling back:
|
||||
*
|
||||
* createTable
|
||||
* renameTable
|
||||
* addColumn
|
||||
* addCustomColumn
|
||||
* renameColumn
|
||||
* addIndex
|
||||
* addForeignKey
|
||||
*
|
||||
* Any other destructive changes will result in an error when trying to
|
||||
* rollback the migration.
|
||||
*
|
||||
* Remember to call "create()" or "update()" and NOT "save()" when working
|
||||
* with the Table class.
|
||||
*/
|
||||
public function change()
|
||||
{
|
||||
$this->table('phone_group')
|
||||
->addColumn('id_user', 'integer', ['null' => false])
|
||||
->addColumn('name', 'string', ['null' => false, 'limit' => 100])
|
||||
->addColumn('created_at', 'timestamp', ['null' => false, 'default' => 'CURRENT_TIMESTAMP'])
|
||||
->addColumn('updated_at', 'timestamp', ['null' => true, 'update' => 'CURRENT_TIMESTAMP'])
|
||||
->addForeignKey('id_user', 'user', 'id', ['delete' => 'CASCADE', 'update' => 'CASCADE'])
|
||||
->create();
|
||||
|
||||
$this->table('phone_group_phone')
|
||||
->addColumn('id_phone_group', 'integer', ['null' => false])
|
||||
->addColumn('id_phone', 'integer', ['null' => false])
|
||||
->addColumn('created_at', 'timestamp', ['null' => false, 'default' => 'CURRENT_TIMESTAMP'])
|
||||
->addColumn('updated_at', 'timestamp', ['null' => true, 'update' => 'CURRENT_TIMESTAMP'])
|
||||
->addForeignKey('id_phone_group', 'phone_group', 'id', ['delete' => 'CASCADE', 'update' => 'CASCADE'])
|
||||
->addForeignKey('id_phone', 'phone', 'id', ['delete' => 'CASCADE', 'update' => 'CASCADE'])
|
||||
->create();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
class AddIdPhoneGroupToScheduled extends AbstractMigration
|
||||
{
|
||||
/**
|
||||
* Change Method.
|
||||
*
|
||||
* Write your reversible migrations using this method.
|
||||
*
|
||||
* More information on writing migrations is available here:
|
||||
* https://book.cakephp.org/phinx/0/en/migrations.html
|
||||
*
|
||||
* The following commands can be used in this method and Phinx will
|
||||
* automatically reverse them when rolling back:
|
||||
*
|
||||
* createTable
|
||||
* renameTable
|
||||
* addColumn
|
||||
* addCustomColumn
|
||||
* renameColumn
|
||||
* addIndex
|
||||
* addForeignKey
|
||||
*
|
||||
* Any other destructive changes will result in an error when trying to
|
||||
* rollback the migration.
|
||||
*
|
||||
* Remember to call "create()" or "update()" and NOT "save()" when working
|
||||
* with the Table class.
|
||||
*/
|
||||
public function change()
|
||||
{
|
||||
$this->table('scheduled')
|
||||
->addColumn('id_phone_group', 'integer', ['null' => true, 'default' => null, 'after' => 'id_phone'])
|
||||
->addForeignKey('id_phone_group', 'phone_group', 'id', ['delete' => 'CASCADE', 'update' => 'CASCADE'])
|
||||
->update();
|
||||
}
|
||||
}
|
||||
42
db/migrations/20230224133515_add_scheduled_tag.php
Normal file
42
db/migrations/20230224133515_add_scheduled_tag.php
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
class AddScheduledTag extends AbstractMigration
|
||||
{
|
||||
/**
|
||||
* Change Method.
|
||||
*
|
||||
* Write your reversible migrations using this method.
|
||||
*
|
||||
* More information on writing migrations is available here:
|
||||
* https://book.cakephp.org/phinx/0/en/migrations.html
|
||||
*
|
||||
* The following commands can be used in this method and Phinx will
|
||||
* automatically reverse them when rolling back:
|
||||
*
|
||||
* createTable
|
||||
* renameTable
|
||||
* addColumn
|
||||
* addCustomColumn
|
||||
* renameColumn
|
||||
* addIndex
|
||||
* addForeignKey
|
||||
*
|
||||
* Any other destructive changes will result in an error when trying to
|
||||
* rollback the migration.
|
||||
*
|
||||
* Remember to call "create()" or "update()" and NOT "save()" when working
|
||||
* with the Table class.
|
||||
*/
|
||||
public function change()
|
||||
{
|
||||
$table = $this->table('scheduled');
|
||||
$table->addColumn('tag', 'string', ['default' => NULL, 'null' => true, 'limit' => 1000])
|
||||
->update();
|
||||
|
||||
$table = $this->table('sended');
|
||||
$table->addColumn('tag', 'string', ['default' => NULL, 'null' => true, 'limit' => 255])
|
||||
->update();
|
||||
}
|
||||
}
|
||||
|
|
@ -144,7 +144,7 @@
|
|||
|
||||
/**
|
||||
* Generate IN query params and values
|
||||
* @param string $values : Values to generate in array from
|
||||
* @param array $values : Values to generate in array from
|
||||
* @return array : Array ['QUERY' => string 'IN(...)', 'PARAMS' => [parameters to pass to execute]]
|
||||
*/
|
||||
protected function _generate_in_from_array ($values)
|
||||
|
|
@ -214,6 +214,11 @@
|
|||
$operator = '>';
|
||||
break;
|
||||
|
||||
case ('%' == $first_char) :
|
||||
$true_fieldname = mb_substr($fieldname, 1);
|
||||
$operator = 'LIKE';
|
||||
break;
|
||||
|
||||
case ('=' == $first_char) :
|
||||
$true_fieldname = mb_substr($fieldname, 1);
|
||||
$operator = '=';
|
||||
|
|
@ -227,8 +232,11 @@
|
|||
//Protect against injection in fieldname
|
||||
$true_fieldname = preg_replace('#[^a-zA-Z0-9_]#', '', $true_fieldname);
|
||||
|
||||
$query = '`' . $true_fieldname . '` ' . $operator . ' :where_' . $true_fieldname;
|
||||
$param = ['where_' . $true_fieldname => $value];
|
||||
// Add a uid to fieldname so we can combine multiple rules on same field
|
||||
$uid = uniqid();
|
||||
|
||||
$query = '`' . $true_fieldname . '` ' . $operator . ' :where_' . $true_fieldname . '_' . $uid;
|
||||
$param = ['where_' . $true_fieldname . '_' . $uid => $value];
|
||||
|
||||
return ['QUERY' => $query, 'PARAM' => $param];
|
||||
}
|
||||
|
|
@ -358,7 +366,6 @@
|
|||
}
|
||||
|
||||
$query = "SELECT COUNT(*) as `count` FROM `" . $table . "` WHERE 1 " . (count($wheres) ? 'AND ' : '') . implode(' AND ', $wheres);
|
||||
|
||||
$query = $this->pdo->prepare($query);
|
||||
|
||||
foreach ($params as $label => &$param)
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@
|
|||
'alert_quota_limit_close' => 0.9,
|
||||
'hide_menus' => '',
|
||||
'force_gsm_alphabet' => 0,
|
||||
'phone_limit' => 0,
|
||||
'phone_priority' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@ namespace models;
|
|||
class Phone extends StandardModel
|
||||
{
|
||||
|
||||
const STATUS_AVAILABLE = 'available';
|
||||
const STATUS_UNAVAILABLE = 'unavailable';
|
||||
const STATUS_NO_CREDIT = 'no_credit';
|
||||
|
||||
/**
|
||||
* Return all phones that belongs to active users
|
||||
*
|
||||
|
|
|
|||
123
models/PhoneGroup.php
Normal file
123
models/PhoneGroup.php
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of RaspiSMS.
|
||||
*
|
||||
* (c) Pierre-Lin Bonnemaison <plebwebsas@gmail.com>
|
||||
*
|
||||
* This source file is subject to the GPL-3.0 license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace models;
|
||||
|
||||
class PhoneGroup extends StandardModel
|
||||
{
|
||||
/**
|
||||
* Return a list of phone groups for a user.
|
||||
* Add a column nb_phone.
|
||||
*
|
||||
* @param int $id_user : user id
|
||||
* @param ?int $limit : Number of entry to return or null
|
||||
* @param ?int $offset : Number of entry to ignore or null
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function list_for_user(int $id_user, $limit, $offset)
|
||||
{
|
||||
$query = '
|
||||
SELECT pg.*, COUNT(pgp.id) as nb_phone
|
||||
FROM `phone_group` as pg
|
||||
LEFT JOIN phone_group_phone as pgp
|
||||
ON pg.id = pgp.id_phone_group
|
||||
WHERE pg.id_user = :id_user
|
||||
GROUP BY pg.id
|
||||
';
|
||||
|
||||
if (null !== $limit)
|
||||
{
|
||||
$limit = (int) $limit;
|
||||
|
||||
$query .= ' LIMIT ' . $limit;
|
||||
if (null !== $offset)
|
||||
{
|
||||
$offset = (int) $offset;
|
||||
$query .= ' OFFSET ' . $offset;
|
||||
}
|
||||
}
|
||||
|
||||
$params = [
|
||||
'id_user' => $id_user,
|
||||
];
|
||||
|
||||
return $this->_run_query($query, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a phone group by his name for a user.
|
||||
*
|
||||
* @param int $id_user : User id
|
||||
* @param string $name : Group name
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_by_name_for_user(int $id_user, string $name)
|
||||
{
|
||||
return $this->_select_one($this->get_table_name(), ['id_user' => $id_user, 'name' => $name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete relations between phone group and phone for a group.
|
||||
*
|
||||
* @param int $id_phone_group : Group id
|
||||
*
|
||||
* @return int : Number of deleted rows
|
||||
*/
|
||||
public function delete_phone_group_phone_relations(int $id_phone_group)
|
||||
{
|
||||
return $this->_delete('phone_group_phone', ['id_phone_group' => $id_phone_group]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a relation between a phone group and a phone.
|
||||
*
|
||||
* @param int $id_phone_group : Phone Group id
|
||||
* @param int $id_phone : Phone id
|
||||
*
|
||||
* @return mixed (bool|int) : False on error, new row id else
|
||||
*/
|
||||
public function insert_phone_group_phone_relation(int $id_phone_group, int $id_phone)
|
||||
{
|
||||
$success = (bool) $this->_insert('phone_group_phone', ['id_phone_group' => $id_phone_group, 'id_phone' => $id_phone]);
|
||||
|
||||
return $success ? $this->_last_id() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get phone groups phones.
|
||||
*
|
||||
* @param int $id_phone_group : Phone Group id
|
||||
*
|
||||
* @return array : Phones of the group
|
||||
*/
|
||||
public function get_phones(int $id_phone_group)
|
||||
{
|
||||
$query = '
|
||||
SELECT *
|
||||
FROM `phone`
|
||||
WHERE id IN (SELECT id_phone FROM `phone_group_phone` WHERE id_phone_group = :id_phone_group)
|
||||
';
|
||||
|
||||
$params = ['id_phone_group' => $id_phone_group];
|
||||
|
||||
return $this->_run_query($query, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return table name.
|
||||
*/
|
||||
protected function get_table_name(): string
|
||||
{
|
||||
return 'phone_group';
|
||||
}
|
||||
}
|
||||
|
|
@ -183,13 +183,35 @@ namespace models;
|
|||
*
|
||||
* @param int $id_user : User id
|
||||
* @param int $id_phone : Phone id we want the number of sended message for
|
||||
* @param \DateTime $since : Date since which we want sended number
|
||||
* @param ?\DateTime $since : Date since which we want sended Number. Default to null.
|
||||
* @param ?\DateTime $before : Date up to which we want sended number. Default to null.
|
||||
* @param ?string $tag_like : Tag to filter sms by, this is not a = but a LIKE operator
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count_since_for_phone_and_user(int $id_user, int $id_phone, \DateTime $since) : int
|
||||
public function count_since_for_phone_and_user(int $id_user, int $id_phone, ?\DateTime $since = null, ?\DateTime $before = null, ?string $tag_like = null) : int
|
||||
{
|
||||
return $this->_count('sended', ['id_user' => $id_user, 'id_phone' => $id_phone, '>=at' => $since->format('c')]);
|
||||
$data = [
|
||||
'id_user' => $id_user,
|
||||
'id_phone' => $id_phone,
|
||||
];
|
||||
|
||||
if ($since)
|
||||
{
|
||||
$data['>=at'] = $since->format('c');
|
||||
}
|
||||
|
||||
if ($before)
|
||||
{
|
||||
$data['<=at'] = $before->format('c');
|
||||
}
|
||||
|
||||
if ($tag_like)
|
||||
{
|
||||
$data['%tag'] = $tag_like;
|
||||
}
|
||||
|
||||
return $this->_count('sended', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
18
routes.php
18
routes.php
|
|
@ -164,6 +164,20 @@
|
|||
'delete' => '/phone/delete/{csrf}/',
|
||||
'edit' => '/phone/edit/',
|
||||
'update' => '/phone/update/{csrf}/',
|
||||
'update_status' => '/phone/update_status/{csrf}/',
|
||||
'json_list' => '/phones.json/',
|
||||
],
|
||||
|
||||
'PhoneGroup' => [
|
||||
'list' => '/phone_group/',
|
||||
'list_json' => '/phone_group/json/',
|
||||
'add' => '/phone_group/add/',
|
||||
'create' => '/phone_group/create/{csrf}/',
|
||||
'delete' => '/phone_group/delete/{csrf}/',
|
||||
'edit' => '/phone_group/edit/',
|
||||
'update' => '/phone_group/update/{csrf}/',
|
||||
'preview' => '/phone_group/preview/{id_group}/',
|
||||
'json_list' => '/phone_group.json/',
|
||||
],
|
||||
|
||||
'Call' => [
|
||||
|
|
@ -194,6 +208,7 @@
|
|||
'/api/list/{entry_type}/',
|
||||
'/api/list/{entry_type}/{page}/',
|
||||
],
|
||||
'get_usage' => '/api/usage/',
|
||||
'post_scheduled' => [
|
||||
'/api/scheduled/',
|
||||
],
|
||||
|
|
@ -206,6 +221,9 @@
|
|||
'post_update_phone' => [
|
||||
'/api/phone/{id}/',
|
||||
],
|
||||
'post_update_phone_status' => [
|
||||
'/api/phone/{id}/status/',
|
||||
],
|
||||
'delete_phone' => [
|
||||
'/api/phone/{id}/',
|
||||
],
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ jQuery(document).ready(function ()
|
|||
{
|
||||
data: '_',
|
||||
render: function (data, type, row, meta) {
|
||||
return '<a class="btn btn-info preview-button" href="#" data-id-group="' + jQuery.fn.dataTable.render.text().display(row.id) + '"><span class="fa fa-eye"></span></a>';
|
||||
return '<a class="btn btn-info preview-button inline" href="#" data-id-group="' + jQuery.fn.dataTable.render.text().display(row.id) + '"><span class="fa fa-eye"></span></a>';
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -145,7 +145,6 @@ jQuery(document).ready(function ()
|
|||
html += ' <div class="preview-contact-number">' + jQuery.fn.dataTable.render.text().display(contact.number) + '</div>'
|
||||
html += ' <code class="preview-contact-data">' + jQuery.fn.dataTable.render.text().display(contact.data) + '</code>'
|
||||
html += '</div>';
|
||||
console.log(contact);
|
||||
}
|
||||
|
||||
jQuery('#preview-text-modal').find('.modal-body').html(html);
|
||||
|
|
|
|||
|
|
@ -110,8 +110,16 @@
|
|||
</li>
|
||||
<?php } ?>
|
||||
<?php if (!in_array('phones', json_decode($_SESSION['user']['settings']['hide_menus'], true) ?? [])) { ?>
|
||||
<li>
|
||||
<a href="javascript:;" data-toggle="collapse" data-target="#phones"><i class="fa fa-fw fa-phone"></i> Téléphones <i class="fa fa-fw fa-caret-down"></i></a>
|
||||
<ul id="phones" class="collapse <?php echo in_array($page, array('phones', 'phone_groups')) ? 'in' : ''; ?>">
|
||||
<li <?php echo $page == 'phones' ? 'class="active"' : ''; ?>>
|
||||
<a href="<?php echo \descartes\Router::url('Phone', 'list'); ?>"><i class="fa fa-fw fa-phone"></i> Téléphones</a>
|
||||
</li>
|
||||
<li <?php echo $page == 'phone_groups' ? 'class="active"' : ''; ?>>
|
||||
<a href="<?php echo \descartes\Router::url('PhoneGroup', 'list'); ?>"><i class="fa fa-list-alt fa-fw"></i> Groupes de Téléphones</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<?php } ?>
|
||||
<?php if (!in_array('settings', json_decode($_SESSION['user']['settings']['hide_menus'], true) ?? [])) { ?>
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@
|
|||
<input required="required" name="name" class="form-control" placeholder="Nom du téléphone" value="<?php $this->s($_SESSION['previous_http_post']['name'] ?? '') ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($_SESSION['user']['settings']['phone_priority']) { ?>
|
||||
<div class="form-group">
|
||||
<label>Priorité d'utilisation du téléphone</label>
|
||||
<p class="italic small help">
|
||||
|
|
@ -56,6 +58,8 @@
|
|||
<input required="required" name="priority" class="form-control" type="number" min="0" placeholder="Priorité d'utilisation" value="<?php $this->s($_SESSION['previous_http_post']['priority'] ?? 0) ?>">
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Type de téléphone</label>
|
||||
<p class="italic small help" id="description-adapter-general">
|
||||
|
|
@ -87,6 +91,8 @@
|
|||
<div id="adapter-data-fields"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($_SESSION['user']['settings']['phone_limit']) { ?>
|
||||
<div class="form-group">
|
||||
<label>Limites des volumes d'envoi du téléphone</label>
|
||||
<p class="italic small help">
|
||||
|
|
@ -96,6 +102,8 @@
|
|||
<div class="text-center"><div class="add-phone-limit-button fa fa-plus-circle"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<a class="btn btn-danger" href="<?php echo \descartes\Router::url('Phone', 'list'); ?>">Annuler</a>
|
||||
<input type="submit" class="btn btn-success" value="Enregistrer le téléphone" />
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
<form action="<?php echo \descartes\Router::url('Phone', 'update', ['csrf' => $_SESSION['csrf']]);?>" method="POST">
|
||||
<?php foreach ($phones as $phone) { ?>
|
||||
<div class="entry-container" data-entry-id="<?php $this->s($phone['id']); ?>">
|
||||
|
||||
<div class="form-group">
|
||||
<label>Nom du téléphone</label>
|
||||
<p class="italic small help">
|
||||
|
|
@ -49,6 +50,8 @@
|
|||
<input required="required" name="phones[<?php $this->s($phone['id']); ?>][name]" class="form-control" placeholder="Nom du téléphone" value="<?php $this->s($phone['name']); ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($_SESSION['user']['settings']['phone_priority']) { ?>
|
||||
<div class="form-group">
|
||||
<label>Priorité d'utilisation du téléphone</label>
|
||||
<p class="italic small help">
|
||||
|
|
@ -58,6 +61,8 @@
|
|||
<input required="required" name="phones[<?php $this->s($phone['id']); ?>][priority]" class="form-control" type="number" min="0" placeholder="Priorité d'utilisation" value="<?php $this->s($phone['priority']) ?>">
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Type de téléphone</label>
|
||||
<p class="italic small help description-adapter-general">
|
||||
|
|
@ -65,13 +70,15 @@
|
|||
</p>
|
||||
<select name="phones[<?php $this->s($phone['id']); ?>][adapter]" class="form-control adapter-select">
|
||||
<?php foreach ($adapters as $adapter) { ?>
|
||||
<?php if ($adapter['meta_hidden'] === false) { ?>
|
||||
<?php if ($adapter['meta_hidden'] === false || $phone['adapter'] == $adapter['meta_classname']) { ?>
|
||||
<option
|
||||
value="<?= $adapter['meta_classname'] ?>"
|
||||
data-description="<?php $this->s($adapter['meta_description']); ?>"
|
||||
data-data-fields="<?php $this->s(json_encode($adapter['meta_data_fields'])); ?>"
|
||||
<?php if ($phone['adapter'] == $adapter['meta_classname']) { ?>
|
||||
<?php if (!$adapter['meta_hide_data']) { ?>
|
||||
data-phone-adapter-data="<?php $this->s($phone['adapter_data']); ?>"
|
||||
<?php } ?>
|
||||
selected
|
||||
<?php } ?>
|
||||
>
|
||||
|
|
@ -92,6 +99,8 @@
|
|||
<div class="adapter-data-fields"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($_SESSION['user']['settings']['phone_limit']) { ?>
|
||||
<div class="form-group">
|
||||
<label>Limites des volumes d'envoi du téléphone</label>
|
||||
<p class="italic small help">
|
||||
|
|
@ -130,6 +139,8 @@
|
|||
<div class="text-center"><div class="add-phone-limit-button fa fa-plus-circle"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
</div>
|
||||
<hr/>
|
||||
<?php } ?>
|
||||
|
|
|
|||
|
|
@ -41,10 +41,14 @@
|
|||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Nom</th>
|
||||
<?php if ($_SESSION['user']['settings']['phone_priority']) { ?>
|
||||
<th>Priorité</th>
|
||||
<?php } ?>
|
||||
<th>Type de téléphone</th>
|
||||
<th>Callbacks</th>
|
||||
<?php if ($_SESSION['user']['settings']['phone_limit']) { ?>
|
||||
<th>Limites</th>
|
||||
<?php } ?>
|
||||
<th class="checkcolumn"><input type="checkbox" id="check-all"/></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -58,6 +62,7 @@
|
|||
</div>
|
||||
<div class="text-right col-xs-6 no-padding">
|
||||
<strong>Action pour la séléction :</strong>
|
||||
<button class="btn btn-default" type="submit" formaction="<?php echo \descartes\Router::url('Phone', 'update_status', ['csrf' => $_SESSION['csrf']]); ?>"><span class="fa fa-refresh"></span> Rafraichir le status</button>
|
||||
<button class="btn btn-default" type="submit" formaction="<?php echo \descartes\Router::url('Phone', 'edit'); ?>"><span class="fa fa-edit"></span> Modifier</button>
|
||||
<button class="btn btn-default btn-confirm" type="submit" formaction="<?php echo \descartes\Router::url('Phone', 'delete', ['csrf' => $_SESSION['csrf']]); ?>"><span class="fa fa-trash-o"></span> Supprimer</button>
|
||||
</div>
|
||||
|
|
@ -90,8 +95,31 @@ jQuery(document).ready(function ()
|
|||
},
|
||||
"columns" : [
|
||||
{data: 'id', render: jQuery.fn.dataTable.render.text()},
|
||||
{data: 'name', render: jQuery.fn.dataTable.render.text()},
|
||||
{
|
||||
data: 'name',
|
||||
render: function (data, type, row, meta) {
|
||||
html = jQuery.fn.dataTable.render.text().display(data)
|
||||
switch (row.status)
|
||||
{
|
||||
case 'available':
|
||||
html += ' - <span class="text-success">Disponible</span>'
|
||||
break;
|
||||
|
||||
case 'unavailable':
|
||||
html += ' - <span class="text-danger">Indisponible</span>'
|
||||
break;
|
||||
|
||||
case 'no_credit':
|
||||
html += ' - <span class="text-warning">Plus de crédit</span>'
|
||||
break;
|
||||
}
|
||||
|
||||
return html
|
||||
},
|
||||
},
|
||||
<?php if ($_SESSION['user']['settings']['phone_priority']) { ?>
|
||||
{data: 'priority', render: jQuery.fn.dataTable.render.text()},
|
||||
<?php } ?>
|
||||
{data: 'adapter', render: jQuery.fn.dataTable.render.text()},
|
||||
{
|
||||
data: '_',
|
||||
|
|
@ -127,6 +155,7 @@ jQuery(document).ready(function ()
|
|||
return html;
|
||||
},
|
||||
},
|
||||
<?php if ($_SESSION['user']['settings']['phone_limit']) { ?>
|
||||
{
|
||||
data: 'limits',
|
||||
render: function (limits) {
|
||||
|
|
@ -182,6 +211,7 @@ jQuery(document).ready(function ()
|
|||
return html;
|
||||
},
|
||||
},
|
||||
<?php } ?>
|
||||
{
|
||||
data: 'id',
|
||||
render: function (data, type, row, meta) {
|
||||
|
|
|
|||
78
templates/phone_group/add.php
Normal file
78
templates/phone_group/add.php
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
//Template dashboard
|
||||
|
||||
$this->render('incs/head', ['title' => 'Groupes de Téléphones - Add'])
|
||||
?>
|
||||
<div id="wrapper">
|
||||
<?php
|
||||
$this->render('incs/nav', ['page' => 'phone_groups'])
|
||||
?>
|
||||
<div id="page-wrapper">
|
||||
<div class="container-fluid">
|
||||
<!-- Page Heading -->
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header">
|
||||
Nouveau groupe de téléphones
|
||||
</h1>
|
||||
<ol class="breadcrumb">
|
||||
<li>
|
||||
<i class="fa fa-dashboard"></i> <a href="<?php echo \descartes\Router::url('Dashboard', 'show'); ?>">Dashboard</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-list-alt"></i> <a href="<?php echo \descartes\Router::url('PhoneGroup', 'list'); ?>">Groupes de téléphones</a>
|
||||
</li>
|
||||
<li class="active">
|
||||
<i class="fa fa-plus"></i> Nouveau
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><i class="fa fa-list-alt fa-fw"></i> Ajout d'un groupe de téléphones</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('PhoneGroup', 'create', ['csrf' => $_SESSION['csrf']]);?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Nom du groupe de téléphone</label>
|
||||
<div class="form-group input-group">
|
||||
<span class="input-group-addon"><span class="fa fa-phone"></span></span>
|
||||
<input name="name" class="form-control" type="text" placeholder="Nom du groupe" autofocus required value="<?php $this->s($_SESSION['previous_http_post']['name'] ?? '') ?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Téléphones du groupe</label>
|
||||
<input class="add-phones form-control" name="phones[]" value="<?php $this->s(json_encode($_SESSION['previous_http_post']['phones'] ?? [])); ?>"/>
|
||||
</div>
|
||||
<a class="btn btn-danger" href="<?php echo \descartes\Router::url('PhoneGroup', 'list'); ?>">Annuler</a>
|
||||
<input type="submit" class="btn btn-success" value="Enregistrer le groupe de téléphones" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
jQuery(document).ready(function()
|
||||
{
|
||||
jQuery('.add-phones').each(function()
|
||||
{
|
||||
jQuery(this).magicSuggest({
|
||||
data: '<?php echo \descartes\Router::url('Phone', 'json_list'); ?>',
|
||||
valueField: 'id',
|
||||
displayField: 'name',
|
||||
name: 'phones[]',
|
||||
maxSelection: null,
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
$this->render('incs/footer');
|
||||
93
templates/phone_group/edit.php
Normal file
93
templates/phone_group/edit.php
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
//Template dashboard
|
||||
|
||||
$this->render('incs/head', ['title' => 'Groupes de Téléphones - Edit'])
|
||||
?>
|
||||
<div id="wrapper">
|
||||
<?php
|
||||
$this->render('incs/nav', ['page' => 'phone_groups'])
|
||||
?>
|
||||
<div id="page-wrapper">
|
||||
<div class="container-fluid">
|
||||
<!-- Page Heading -->
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header">
|
||||
Modification groupes de téléphones
|
||||
</h1>
|
||||
<ol class="breadcrumb">
|
||||
<li>
|
||||
<i class="fa fa-dashboard"></i> <a href="<?php echo \descartes\Router::url('Dashboard', 'show'); ?>">Dashboard</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-list-alt"></i> <a href="<?php echo \descartes\Router::url('PhoneGroup', 'list'); ?>">Groupes de téléphones</a>
|
||||
</li>
|
||||
<li class="active">
|
||||
<i class="fa fa-edit"></i> Modifier
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><i class="fa fa-edit fa-fw"></i> Modification des groupes de téléphones</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('PhoneGroup', 'update', ['csrf' => $_SESSION['csrf']]);?>" method="POST">
|
||||
<?php
|
||||
foreach ($phone_groups as $phone_group)
|
||||
{
|
||||
$phones = array();
|
||||
foreach ($phone_group['phones'] as $phone)
|
||||
{
|
||||
$phones[] = (int)$phone['id'];
|
||||
}
|
||||
$phones = json_encode($phones);
|
||||
|
||||
?>
|
||||
<input name="phone_groups[<?php $this->s($phone_group['id']); ?>][phone_group][id]" type="hidden" value="<?php $this->s($phone_group['id']); ?>">
|
||||
<div class="form-group">
|
||||
<label>Nom du groupe de téléphone</label>
|
||||
<div class="form-group input-group">
|
||||
<span class="input-group-addon"><span class="fa fa-user"></span></span>
|
||||
<input name="phone_groups[<?php $this->s($phone_group['id']); ?>][name]" class="form-control" type="text" placeholder="Nom du groupe" autofocus required value="<?php $this->s($phone_group['name']); ?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Téléphones du groupe</label>
|
||||
<input class="add-phones form-control" name="phone_groups[<?php $this->s($phone_group['id']); ?>][phones_ids][]" value="<?php $this->s($phones); ?>"/>
|
||||
</div>
|
||||
<hr/>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<a class="btn btn-danger" href="<?php echo \descartes\Router::url('PhoneGroup', 'list'); ?>">Annuler</a>
|
||||
<input type="submit" class="btn btn-success" value="Enregistrer le groupe de téléphones" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
jQuery(document).ready(function()
|
||||
{
|
||||
jQuery('.add-phones').each(function()
|
||||
{
|
||||
jQuery(this).magicSuggest({
|
||||
data: '<?php echo \descartes\Router::url('Phone', 'json_list'); ?>',
|
||||
valueField: 'id',
|
||||
displayField: 'name',
|
||||
maxSelection: null,
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
$this->render('incs/footer');
|
||||
159
templates/phone_group/list.php
Normal file
159
templates/phone_group/list.php
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
<?php
|
||||
//Template dashboard
|
||||
|
||||
$this->render('incs/head', ['title' => 'Groupes de Téléphones - Show All'])
|
||||
?>
|
||||
<div id="wrapper">
|
||||
<?php
|
||||
$this->render('incs/nav', ['page' => 'phone_groups'])
|
||||
?>
|
||||
<div id="page-wrapper">
|
||||
<div class="container-fluid">
|
||||
<!-- Page Heading -->
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header">
|
||||
Dashboard <small>Groupes de téléphones</small>
|
||||
</h1>
|
||||
<ol class="breadcrumb">
|
||||
<li>
|
||||
<i class="fa fa-dashboard"></i> <a href="<?php echo \descartes\Router::url('Dashboard', 'show'); ?>">Dashboard</a>
|
||||
</li>
|
||||
<li class="active">
|
||||
<i class="fa fa-list-alt"></i> Groupes de téléphones
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><i class="fa fa-list-alt fa-fw"></i> Liste des groupes de téléphones</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form method="GET">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered table-hover table-striped datatable" id="table-groupes">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nom</th>
|
||||
<th>Nombre de téléphones</th>
|
||||
<th>Date de création</th>
|
||||
<th>Dernière modification</th>
|
||||
<th>Preview</th>
|
||||
<th class="checkcolumn"><input type="checkbox" id="check-all"/></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<div class="col-xs-6 no-padding">
|
||||
<a class="btn btn-success" href="<?php echo \descartes\Router::url('PhoneGroup', 'add'); ?>"><span class="fa fa-plus"></span> Ajouter un groupe de téléphones</a>
|
||||
</div>
|
||||
<div class="text-right col-xs-6 no-padding">
|
||||
<strong>Action pour la séléction :</strong>
|
||||
<button class="btn btn-default" type="submit" formaction="<?php echo \descartes\Router::url('PhoneGroup', 'edit'); ?>"><span class="fa fa-edit"></span> Modifier</button>
|
||||
<button class="btn btn-default btn-confirm" type="submit" formaction="<?php echo \descartes\Router::url('PhoneGroup', 'delete', ['csrf' => $_SESSION['csrf']]); ?>"><span class="fa fa-trash-o"></span> Supprimer</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" tabindex="-1" id="preview-text-modal">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">Prévisualisation des téléphones</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
jQuery(document).ready(function ()
|
||||
{
|
||||
jQuery('.datatable').DataTable({
|
||||
"pageLength": 25,
|
||||
"lengthMenu": [[25, 50, 100, 1000, 10000, -1], [25, 50, 100, 1000, 10000, "All"]],
|
||||
"language": {
|
||||
"url": HTTP_PWD + "/assets/js/datatables/french.json",
|
||||
},
|
||||
"columnDefs": [{
|
||||
'targets': 'checkcolumn',
|
||||
'orderable': false,
|
||||
}],
|
||||
|
||||
"ajax": {
|
||||
'url': '<?php echo \descartes\Router::url('PhoneGroup', 'list_json'); ?>',
|
||||
'dataSrc': 'data',
|
||||
},
|
||||
"columns" : [
|
||||
{data: 'name', render: jQuery.fn.dataTable.render.text()},
|
||||
{data: 'nb_phone', render: jQuery.fn.dataTable.render.text()},
|
||||
{data: 'created_at'},
|
||||
{data: 'updated_at'},
|
||||
{
|
||||
data: '_',
|
||||
render: function (data, type, row, meta) {
|
||||
return '<a class="btn btn-info preview-button inline" href="#" data-id-group="' + jQuery.fn.dataTable.render.text().display(row.id) + '"><span class="fa fa-eye"></span></a>';
|
||||
},
|
||||
},
|
||||
{
|
||||
data: 'id',
|
||||
render: function (data, type, row, meta) {
|
||||
return '<input name="ids[]" type="checkbox" value="' + data + '">';
|
||||
},
|
||||
},
|
||||
],
|
||||
"deferRender": true
|
||||
});
|
||||
|
||||
jQuery('body').on('click', '.preview-button', function (e)
|
||||
{
|
||||
e.preventDefault();
|
||||
var group_id = jQuery(this).attr('data-id-group');
|
||||
|
||||
jQuery.ajax({
|
||||
type: "GET",
|
||||
url: HTTP_PWD + '/phone_group/preview/' + group_id + '/',
|
||||
success: function (data) {
|
||||
if (!data.success) {
|
||||
jQuery('#preview-text-modal').find('.modal-body').text(data.result);
|
||||
} else {
|
||||
html = '';
|
||||
|
||||
for (phone of data.result)
|
||||
{
|
||||
html += '<div class="preview-phone well">';
|
||||
html += ' <div class="preview-phone-name"><span class="bold">Nom : </span>' + jQuery.fn.dataTable.render.text().display(phone.name) + '</div>'
|
||||
html += ' <div class="preview-phone-adapter"><span class="bold">Type : </span>' + jQuery.fn.dataTable.render.text().display(phone.adapter_name) + '</div>'
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
jQuery('#preview-text-modal').find('.modal-body').html(html);
|
||||
}
|
||||
jQuery('#preview-text-modal').modal({'keyboard': true});
|
||||
},
|
||||
dataType: 'json'
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
$this->render('incs/footer');
|
||||
|
|
@ -131,14 +131,32 @@
|
|||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<?php if (count($phones)) { ?>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Tag à associé à la campagne</label>
|
||||
<p class="italic small help">
|
||||
Vous pouvez renseigner une chaine de caractère qui sera associée à tous les SMS envoyés. Utile pour associer un identifiant interne à vos systèmes. Laissez vide si vous ne voulez pas associé de chaine.
|
||||
</p>
|
||||
<div class="form-group">
|
||||
<input name="tag" class="form-control" type="text" placeholder="Ex: region-001" maxlength="255">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (count($phones) || count($phone_groups)) { ?>
|
||||
<div class="form-group">
|
||||
<label>Numéro à employer : </label>
|
||||
<select name="id_phone" class="form-control">
|
||||
<option value="">N'importe lequel</option>
|
||||
<optgroup label="Téléphones">
|
||||
<?php foreach ($phones as $phone) { ?>
|
||||
<option value="<?php $this->s($phone['id']); ?>" <?= ($_SESSION['previous_http_post']['id_phone'] ?? '') == $phone['id'] ? 'selected' : '' ?>><?php $this->s($phone['name']); ?></option>
|
||||
<option value="phone_<?php $this->s($phone['id']); ?>" <?= ($_SESSION['previous_http_post']['id_phone'] ?? '') == ('phone_' . $phone['id']) ? 'selected' : '' ?>><?php $this->s($phone['name']); ?></option>
|
||||
<?php } ?>
|
||||
</optgroup>
|
||||
<optgroup label="Groupes de téléphones">
|
||||
<?php foreach ($phone_groups as $phone_group) { ?>
|
||||
<option value="phonegroup_<?php $this->s($phone_group['id']); ?>" <?= ($_SESSION['previous_http_post']['id_phone'] ?? '') == ('phonegroup_' . $phone_group['id']) ? 'selected' : '' ?>><?php $this->s($phone_group['name']); ?></option>
|
||||
<?php } ?>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
|
|
|||
|
|
@ -152,13 +152,29 @@
|
|||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<div class="form-group">
|
||||
<label>Tag à associé à la campagne</label>
|
||||
<p class="italic small help">
|
||||
Vous pouvez renseigner une chaine de caractère qui sera associée à tous les SMS envoyés. Utile pour associer un identifiant interne à vos systèmes. Laissez vide si vous ne voulez pas associé de chaine.
|
||||
</p>
|
||||
<div class="form-group">
|
||||
<input name="scheduleds[<?php $this->s($scheduled['id']); ?>][tag]" class="form-control" type="text" placeholder="Ex: region-001" maxlength="255" value="<?php $this->s($scheduled['tag']); ?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Numéro à employer : </label>
|
||||
<select name="scheduleds[<?php $this->s($scheduled['id']); ?>][id_phone]" class="form-control">
|
||||
<option <?php echo ($scheduled['id_phone'] ? '' : 'selected="selected"'); ?> value="">N'importe lequel</option>
|
||||
<optgroup label="Téléphones">
|
||||
<?php foreach ($phones as $phone) { ?>
|
||||
<option <?php echo ($scheduled['id_phone'] == $phone['id'] ? 'selected="selected"' : '' ); ?> value="<?php $this->s($phone['id']); ?>"><?php $this->s($phone['name']); ?></option>
|
||||
<option <?php echo (($scheduled['id_phone'] && $scheduled['id_phone'] == $phone['id']) ? 'selected="selected"' : '' ); ?> value="phone_<?php $this->s($phone['id']); ?>"><?php $this->s($phone['name']); ?></option>
|
||||
<?php } ?>
|
||||
</optgroup>
|
||||
<optgroup label="Groupes de téléphones">
|
||||
<?php foreach ($phone_groups as $phone_group) { ?>
|
||||
<option <?php echo (($scheduled['id_phone_group'] && $scheduled['id_phone_group'] == $phone_group['id']) ? 'selected="selected"' : '' ); ?> value="phonegroup_<?php $this->s($phone_group['id']); ?>"><?php $this->s($phone_group['name']); ?></option>
|
||||
<?php } ?>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<hr/>
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
<th>Expéditeur</th>
|
||||
<th>Destinataire</th>
|
||||
<th>Message</th>
|
||||
<th>Tag</th>
|
||||
<th>Date</th>
|
||||
<th>Statut</th>
|
||||
<th class="checkcolumn"><input type="checkbox" id="check-all"/></th>
|
||||
|
|
@ -74,7 +75,7 @@ jQuery(document).ready(function ()
|
|||
"url": HTTP_PWD + "/assets/js/datatables/french.json",
|
||||
},
|
||||
"orderMulti": false,
|
||||
"order": [[3, "desc"]],
|
||||
"order": [[4, "desc"]],
|
||||
"columnDefs": [{
|
||||
'targets': 'checkcolumn',
|
||||
'orderable': false,
|
||||
|
|
@ -111,6 +112,7 @@ jQuery(document).ready(function ()
|
|||
return jQuery.fn.dataTable.render.text().display(data);
|
||||
},
|
||||
},
|
||||
{data: 'tag', render: jQuery.fn.dataTable.render.text()},
|
||||
{data: 'at', render: jQuery.fn.dataTable.render.text()},
|
||||
{
|
||||
data: 'status',
|
||||
|
|
|
|||
|
|
@ -37,16 +37,13 @@
|
|||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-share fa-fw"></i> Transfert des SMS par e-mail</h4>
|
||||
<h4 class="panel-title"><i class="fa fa-phone fa-fw"></i> Pays par défaut numéros internationaux</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'transfer', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'default_phone_country', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Transfert activé : </label>
|
||||
<select name="setting_value" class="form-control">
|
||||
<option value="0">Non</option>
|
||||
<option value="1" <?php echo $_SESSION['user']['settings']['transfer'] ? 'selected' : ''; ?>>Oui</option>
|
||||
</select>
|
||||
<label>Code du pays (norme ISO 3166-1 alpha-2) : </label>
|
||||
<input name="setting_value" class="form-control" value="<?php $this->s($_SESSION['user']['settings']['default_phone_country']); ?>" />
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
|
|
@ -54,6 +51,47 @@
|
|||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-phone fa-fw"></i> Pays préférés numéros internationaux</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'preferred_phone_country', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Code des pays (norme ISO 3166-1 alpha-2) séparés par des virgules : </label>
|
||||
<input name="setting_value" class="form-control" value="<?php $this->s($_SESSION['user']['settings']['preferred_phone_country']); ?>" />
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-flag fa-fw"></i> Pays autorisés pour l'envoi</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'authorized_phone_country', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Code des pays (norme ISO 3166-1 alpha-2) séparés par des virgules (laissez vide pour tout autoriser) : </label>
|
||||
<input name="setting_value" class="form-control" value="<?php $this->s($_SESSION['user']['settings']['authorized_phone_country']); ?>" />
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-font fa-fw"></i> Alphabet SMS optimisé</h4>
|
||||
|
|
@ -73,6 +111,9 @@
|
|||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-picture-o fa-fw"></i> Support des MMS</h4>
|
||||
|
|
@ -92,106 +133,20 @@
|
|||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-link fa-fw"></i> Détection des URL dans les discussions</h4>
|
||||
<h4 class="panel-title"><i class="fa fa-flash fa-fw"></i> Support des SMS Flash</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'detect_url', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'sms_flash', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Détection activé : </label>
|
||||
<label>SMS Flash activé : </label>
|
||||
<select name="setting_value" class="form-control">
|
||||
<option value="0">Non</option>
|
||||
<option value="1" <?php echo $_SESSION['user']['settings']['detect_url'] ? 'selected' : ''; ?>>Oui</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-phone fa-fw"></i> Pays préférés numéros internationaux</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'preferred_phone_country', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Code des pays (norme ISO 3166-1 alpha-2) séparés par des virgules : </label>
|
||||
<input name="setting_value" class="form-control" value="<?php $this->s($_SESSION['user']['settings']['preferred_phone_country']); ?>" />
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-flag fa-fw"></i> Pays autorisés pour l'envoi</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'authorized_phone_country', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Code des pays (norme ISO 3166-1 alpha-2) séparés par des virgules (laissez vide pour tout autoriser) : </label>
|
||||
<input name="setting_value" class="form-control" value="<?php $this->s($_SESSION['user']['settings']['authorized_phone_country']); ?>" />
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-music fa-fw"></i> Son sur reception d'un SMS</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'sms_reception_sound', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Jouer un son quand vous recevez un SMS : </label>
|
||||
<select name="setting_value" class="form-control">
|
||||
<option value="0">Non</option>
|
||||
<option value="1" <?php echo $_SESSION['user']['settings']['sms_reception_sound'] ? 'selected' : ''; ?>>Oui</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-exclamation-triangle fa-fw"></i> Alerte limite de SMS atteinte</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'alert_quota_limit_reached', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Recevoir un e-mail quand la limite de SMS est atteinte :</label>
|
||||
<select name="setting_value" class="form-control">
|
||||
<option value="0">Non</option>
|
||||
<option value="1" <?php echo $_SESSION['user']['settings']['alert_quota_limit_reached'] == 1 ? 'selected' : ''; ?>>Oui</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-question-circle fa-fw"></i> Affichage de l'aide</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'display_help', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Afficher l'aide : </label>
|
||||
<select name="setting_value" class="form-control">
|
||||
<option value="0">Non</option>
|
||||
<option value="1" <?php echo $_SESSION['user']['settings']['display_help'] ? 'selected' : ''; ?>>Oui</option>
|
||||
<option value="1" <?php echo $_SESSION['user']['settings']['sms_flash'] ? 'selected' : ''; ?>>Oui</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
|
|
@ -201,6 +156,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
|
|
@ -221,79 +177,9 @@
|
|||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-plug fa-fw"></i> Activation de Webhooks</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'webhook', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Webhooks activé : </label>
|
||||
<select name="setting_value" class="form-control">
|
||||
<option value="0">Non</option>
|
||||
<option value="1" <?php echo $_SESSION['user']['settings']['webhook'] ? 'selected' : ''; ?>>Oui</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-phone fa-fw"></i> Pays par défaut numéros internationaux</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'default_phone_country', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Code du pays (norme ISO 3166-1 alpha-2) : </label>
|
||||
<input name="setting_value" class="form-control" value="<?php $this->s($_SESSION['user']['settings']['default_phone_country']); ?>" />
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-flash fa-fw"></i> Support des SMS Flash</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'sms_flash', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>SMS Flash activé : </label>
|
||||
<select name="setting_value" class="form-control">
|
||||
<option value="0">Non</option>
|
||||
<option value="1" <?php echo $_SESSION['user']['settings']['sms_flash'] ? 'selected' : ''; ?>>Oui</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-bullseye fa-fw"></i> Support des groupes conditionnels</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'conditional_group', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Groupes conditionnels activés : </label>
|
||||
<select name="setting_value" class="form-control">
|
||||
<option value="0">Non</option>
|
||||
<option value="1" <?php echo $_SESSION['user']['settings']['conditional_group'] ? 'selected' : ''; ?>>Oui</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-code fa-fw"></i> Support du templating</h4>
|
||||
|
|
@ -313,6 +199,141 @@
|
|||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-bullseye fa-fw"></i> Support des groupes conditionnels</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'conditional_group', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Groupes conditionnels activés : </label>
|
||||
<select name="setting_value" class="form-control">
|
||||
<option value="0">Non</option>
|
||||
<option value="1" <?php echo $_SESSION['user']['settings']['conditional_group'] ? 'selected' : ''; ?>>Oui</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-thermometer-3 fa-fw"></i> Support des limites d'envoi par téléphones</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'phone_limit', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Limites d'envoi par téléphones activées : </label>
|
||||
<select name="setting_value" class="form-control">
|
||||
<option value="0">Non</option>
|
||||
<option value="1" <?php echo $_SESSION['user']['settings']['phone_limit'] ? 'selected' : ''; ?>>Oui</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-sort-numeric-desc fa-fw"></i> Support des téléphones prioritaires</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'phone_priority', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Téléphones prioritaires activés : </label>
|
||||
<select name="setting_value" class="form-control">
|
||||
<option value="0">Non</option>
|
||||
<option value="1" <?php echo $_SESSION['user']['settings']['phone_priority'] ? 'selected' : ''; ?>>Oui</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-plug fa-fw"></i> Activation de Webhooks</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'webhook', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Webhooks activé : </label>
|
||||
<select name="setting_value" class="form-control">
|
||||
<option value="0">Non</option>
|
||||
<option value="1" <?php echo $_SESSION['user']['settings']['webhook'] ? 'selected' : ''; ?>>Oui</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-share fa-fw"></i> Transfert des SMS par e-mail</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'transfer', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Transfert activé : </label>
|
||||
<select name="setting_value" class="form-control">
|
||||
<option value="0">Non</option>
|
||||
<option value="1" <?php echo $_SESSION['user']['settings']['transfer'] ? 'selected' : ''; ?>>Oui</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-exclamation-triangle fa-fw"></i> Alerte limite de SMS atteinte</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'alert_quota_limit_reached', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Recevoir un e-mail quand la limite de SMS est atteinte :</label>
|
||||
<select name="setting_value" class="form-control">
|
||||
<option value="0">Non</option>
|
||||
<option value="1" <?php echo $_SESSION['user']['settings']['alert_quota_limit_reached'] == 1 ? 'selected' : ''; ?>>Oui</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-exclamation fa-fw"></i> Alerte limite de SMS proche</h4>
|
||||
|
|
@ -337,6 +358,75 @@
|
|||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-music fa-fw"></i> Son sur reception d'un SMS</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'sms_reception_sound', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Jouer un son quand vous recevez un SMS : </label>
|
||||
<select name="setting_value" class="form-control">
|
||||
<option value="0">Non</option>
|
||||
<option value="1" <?php echo $_SESSION['user']['settings']['sms_reception_sound'] ? 'selected' : ''; ?>>Oui</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-link fa-fw"></i> Détection des URL dans les discussions</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'detect_url', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Détection activé : </label>
|
||||
<select name="setting_value" class="form-control">
|
||||
<option value="0">Non</option>
|
||||
<option value="1" <?php echo $_SESSION['user']['settings']['detect_url'] ? 'selected' : ''; ?>>Oui</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-question-circle fa-fw"></i> Affichage de l'aide</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'display_help', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
|
||||
<div class="form-group">
|
||||
<label>Afficher l'aide : </label>
|
||||
<select name="setting_value" class="form-control">
|
||||
<option value="0">Non</option>
|
||||
<option value="1" <?php echo $_SESSION['user']['settings']['display_help'] ? 'selected' : ''; ?>>Oui</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><i class="fa fa-eye-slash fa-fw"></i> Cacher des menus</h4>
|
||||
|
|
@ -346,7 +436,7 @@
|
|||
<input type="hidden" name="allow_no_value" value="1" />
|
||||
<div class="form-group">
|
||||
<label>Cacher certains menus à l'utilisateur (ces menus restent accessibles par l'URL) : </label>
|
||||
<input name="setting_value[]" class="add-hide-menus form-control" type="text" placeholder="Menus à cacher" autofocus value="<?php $this->s($_SESSION['user']['settings']['hide_menus']); ?>">
|
||||
<input name="setting_value[]" class="add-hide-menus form-control" type="text" placeholder="Menus à cacher" value="<?php $this->s($_SESSION['user']['settings']['hide_menus']); ?>">
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button class="btn btn-success">Mettre à jour les données</button>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue