Added content JSON structure parser base, Added images, Added Glider.js, Fixed typos
Update .gitignore, content.php, and 21 more files...
5
.gitignore
vendored
@@ -2,10 +2,9 @@
|
||||
.idea/
|
||||
|
||||
# Static resources
|
||||
resources/Azias/imgs/*.exe
|
||||
resources/Azias/imgs/*.url
|
||||
resources/FontAwesomePro/
|
||||
resources/GoogleFonts/
|
||||
*.exe
|
||||
*.url
|
||||
|
||||
# Other folders (Will be removed once the content system is finished !)
|
||||
# /files/*/
|
||||
|
@@ -11,6 +11,8 @@ include_once 'langs.php';
|
||||
// This helper requires PHP 8 or newer !
|
||||
|
||||
$SHOW_CONTENT_DEBUG_CARD = false;
|
||||
$PRINT_CONTENT_DEBUG_INFO_TEXT_ELEMENTS = true;
|
||||
$PRINT_CONTENT_DEBUG_ERROR_TEXT_ELEMENTS = true;
|
||||
|
||||
// Defining constants and enums.
|
||||
abstract class ContentDisplayType {
|
||||
@@ -130,4 +132,211 @@ function endMainCard() {
|
||||
echo('</div>');
|
||||
}
|
||||
|
||||
function getContentItemText(array $contentNode, bool $italicOnError = true, bool $returnMissingAsEmpty = false) : string {
|
||||
global $user_language, $default_language;
|
||||
if(array_key_exists("key", $contentNode)) {
|
||||
return localize($contentNode["key"]);
|
||||
} elseif(array_key_exists($user_language, $contentNode)) {
|
||||
return $contentNode[$user_language];
|
||||
} elseif(array_key_exists($default_language, $contentNode)) {
|
||||
return $contentNode[$default_language];
|
||||
} else {
|
||||
if($returnMissingAsEmpty) {
|
||||
return "";
|
||||
}
|
||||
if($italicOnError) {
|
||||
return '<i>'.localize("error.content.data.no.title").'</i>';
|
||||
} else {
|
||||
return localize("error.content.data.no.title");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function printInfoTextElement(string $text) : void {
|
||||
global $PRINT_CONTENT_DEBUG_INFO_TEXT_ELEMENTS;
|
||||
if($PRINT_CONTENT_DEBUG_INFO_TEXT_ELEMENTS) {
|
||||
echo('<h3 class="m-0 font-size-20 text-primary font-weight-semi-bold">'.$text.'</h3>');
|
||||
}
|
||||
}
|
||||
|
||||
function printErrorTextElement(string $text) : void {
|
||||
global $PRINT_CONTENT_DEBUG_ERROR_TEXT_ELEMENTS;
|
||||
if($PRINT_CONTENT_DEBUG_ERROR_TEXT_ELEMENTS) {
|
||||
echo('<h3 class="m-0 font-size-20 text-center text-danger font-weight-semi-bold">'.$text.'</h3>');
|
||||
}
|
||||
}
|
||||
|
||||
function createElementNode(mixed $elementNode) : void {
|
||||
// Checking if we actually have a JSON object.
|
||||
if(!is_array($elementNode)) {
|
||||
echo('<p>Not array node !</p>');
|
||||
return;
|
||||
}
|
||||
if(!array_key_exists("type", $elementNode)) {
|
||||
echo('<p>No "type" member found in node !</p>');
|
||||
return;
|
||||
}
|
||||
|
||||
switch($elementNode["type"]) {
|
||||
case "table":
|
||||
//printInfoTextElement('table item type');
|
||||
|
||||
// Reading and processing the modifiers
|
||||
$_modNoOuterPadding = false;
|
||||
$_modStriped = false;
|
||||
$_modHover = false;
|
||||
$_modInnerBordered = false;
|
||||
if(array_key_exists("modifiers", $elementNode)) {
|
||||
for ($i = 0; $i < count($elementNode["modifiers"]); $i++) {
|
||||
//printInfoTextElement('>> Modifier: '.$elementNode["modifiers"][$i]);
|
||||
switch($elementNode["modifiers"][$i]) {
|
||||
case "no-outer-padding":
|
||||
// Removes the rounding on the external edges.
|
||||
$_modNoOuterPadding = true;
|
||||
break;
|
||||
case "striped":
|
||||
// Removes the internal padding and adds 0.01em to the top to prevent gaps from margins.
|
||||
$_modStriped = true;
|
||||
break;
|
||||
case "hover":
|
||||
// Removes the standard top margin.
|
||||
$_modHover = true;
|
||||
break;
|
||||
case "inner-bordered":
|
||||
// Removes the standard top margin.
|
||||
$_modInnerBordered = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Preparing table
|
||||
echo('<table class="table'.($_modNoOuterPadding?" table-no-outer-padding":"").($_modStriped?" table-striped":"").
|
||||
($_modHover?" table-hover":"").($_modInnerBordered?" table-inner-bordered":"").'">');
|
||||
|
||||
// Creating "thead"
|
||||
if(array_key_exists("head", $elementNode)) {
|
||||
echo('<thead><tr>');
|
||||
for ($iTableHead = 0; $iTableHead < count($elementNode["head"]); $iTableHead++) {
|
||||
echo('<th>');
|
||||
if(array_key_exists("parts", $elementNode["head"][$iTableHead])) {
|
||||
for ($iPart = 0; $iPart < count($elementNode["head"][$iTableHead]["parts"]); $iPart++) {
|
||||
createElementNode($elementNode["head"][$iTableHead]["parts"][$iPart]);
|
||||
}
|
||||
} else {
|
||||
echo(getContentItemText($elementNode["head"][$iTableHead], false, true));
|
||||
}
|
||||
echo('</th>');
|
||||
}
|
||||
echo('</tr></thead>');
|
||||
}
|
||||
|
||||
// Creating "tbody"
|
||||
if(array_key_exists("body", $elementNode)) {
|
||||
echo('<tbody>');
|
||||
for ($iTableBodyRow = 0; $iTableBodyRow < count($elementNode["body"]); $iTableBodyRow++) {
|
||||
echo('<tr>');
|
||||
for ($iTableBodyCell = 0; $iTableBodyCell < count($elementNode["body"][$iTableBodyRow]); $iTableBodyCell++) {
|
||||
$_cellColSpan = 1;
|
||||
$_cellRowSpan = 1;
|
||||
if(array_key_exists("colspan", $elementNode["body"][$iTableBodyRow][$iTableBodyCell])) {
|
||||
$_cellColSpan = $elementNode["body"][$iTableBodyRow][$iTableBodyCell]["colspan"];
|
||||
}
|
||||
if(array_key_exists("rowspan", $elementNode["body"][$iTableBodyRow][$iTableBodyCell])) {
|
||||
$_cellRowSpan = $elementNode["body"][$iTableBodyRow][$iTableBodyCell]["rowspan"];
|
||||
}
|
||||
|
||||
echo('<td'.($_cellColSpan>1?' colspan="'.$_cellColSpan.'"':'').($_cellRowSpan>1?' rowspan="'.$_cellRowSpan.'"':'').'>');
|
||||
if(array_key_exists("parts", $elementNode["body"][$iTableBodyRow][$iTableBodyCell])) {
|
||||
for ($iPart = 0; $iPart < count($elementNode["body"][$iTableBodyRow][$iTableBodyCell]["parts"]); $iPart++) {
|
||||
createElementNode($elementNode["body"][$iTableBodyRow][$iTableBodyCell]["parts"][$iPart]);
|
||||
}
|
||||
} else {
|
||||
echo(getContentItemText($elementNode["body"][$iTableBodyRow][$iTableBodyCell], false, true));
|
||||
}
|
||||
echo('</td>');
|
||||
}
|
||||
echo('</tr>');
|
||||
}
|
||||
echo('</tbody>');
|
||||
}
|
||||
|
||||
// Ending table
|
||||
echo('</table>');
|
||||
|
||||
break;
|
||||
case "collapse":
|
||||
//printInfoTextElement('collapse item type');
|
||||
|
||||
// Preparing some stuff
|
||||
$_title = '<i>'.localize("error.content.data.no.title").'</i>';
|
||||
$_subtitle = '';
|
||||
if(array_key_exists("title", $elementNode)) {
|
||||
$_title = getContentItemText($elementNode["title"], true, true);
|
||||
}
|
||||
if(array_key_exists("subtitle", $elementNode)) {
|
||||
$_subtitle = getContentItemText($elementNode["subtitle"], true, true);
|
||||
}
|
||||
//printInfoTextElement('> title: "'.$_title);
|
||||
//printInfoTextElement('> subtitle: "'.$_subtitle);
|
||||
|
||||
// Reading and processing the modifiers
|
||||
$_modNoRounding = false;
|
||||
$_modNoContentPadding = false;
|
||||
$_modNoTopMargin = false;
|
||||
$_modIsClosed = false;
|
||||
if(array_key_exists("modifiers", $elementNode)) {
|
||||
for ($i = 0; $i < count($elementNode["modifiers"]); $i++) {
|
||||
//printInfoTextElement('>> Modifier: '.$elementNode["modifiers"][$i]);
|
||||
switch($elementNode["modifiers"][$i]) {
|
||||
case "no-rounding":
|
||||
// Removes the rounding on the external edges.
|
||||
$_modNoRounding = true;
|
||||
break;
|
||||
case "no-padding-content":
|
||||
// Removes the internal padding and adds 0.01em to the top to prevent gaps from margins.
|
||||
$_modNoContentPadding = true;
|
||||
break;
|
||||
case "no-top-margin":
|
||||
// Removes the standard top margin.
|
||||
$_modNoTopMargin = true;
|
||||
break;
|
||||
case "closed":
|
||||
// Close the collapse by default.
|
||||
$_modIsClosed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Starting the collapse
|
||||
echo('<details class="collapse-panel w-full'.($_modNoTopMargin?"":" mt-20").'" '.($_modIsClosed?"closed":"open").'>');
|
||||
echo('<summary class="collapse-header p-10 px-15 text-truncate without-arrow'.($_modNoRounding?" rounded-0":"").' border-left-0 border-right-0">');
|
||||
echo('<h4 class="font-size-16 m-0 align-middle no-select"><i class="fad fa-angle-down hidden-collapse-open font-size-24"></i>');
|
||||
echo('<i class="fad fa-angle-up hidden-collapse-closed font-size-24"></i>');
|
||||
echo('<span class="font-weight-semi-bold align-top"> '.$_title.'<span class="ml-20 text-muted">'.$_subtitle.'</span></span>');
|
||||
echo('</h4></summary><div class="collapse-content'.($_modNoContentPadding?" p-0 py-01":"").($_modNoRounding?" rounded-0":"").' border-0 border-bottom">');
|
||||
|
||||
// Rendering sub-elements
|
||||
if(array_key_exists("parts", $elementNode)) {
|
||||
//printInfoTextElement('> Processing sub-parts');
|
||||
for ($i = 0; $i < count($elementNode["parts"]); $i++) {
|
||||
createElementNode($elementNode["parts"][$i]);
|
||||
}
|
||||
//printInfoTextElement('> Done processing sub-parts');
|
||||
} else {
|
||||
printErrorTextElement(localize("error.content.data.no.subpart"));
|
||||
}
|
||||
|
||||
// Ending the collapse
|
||||
echo('</div></details>');
|
||||
//printInfoTextElement('end of collapse');
|
||||
|
||||
break;
|
||||
default:
|
||||
printErrorTextElement(sprintf(localize("error.content.data.part.unknown"), $elementNode["type"]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
@@ -106,8 +106,12 @@
|
||||
"error.content.tags.alphanumeric": "One of the tags given in the \"tags\" URL parameter is not a valid alphanumeric string.",
|
||||
"error.content.detect.type": "The type of requested content couldn't be determined.",
|
||||
"error.content.id.alphanumeric": "The requested resource's ID isn't valid.",
|
||||
"error.content.data.not.exist": "The requested resource's doesn't have an associated item file.",
|
||||
"error.content.data.not.exist": "The requested content doesn't have an internal item file.",
|
||||
"error.content.data.no.title": "No title found !",
|
||||
"error.content.data.no.tags": "No tags found !",
|
||||
"error.content.data.no.parts": "No content parts were found for this content !",
|
||||
"error.content.data.no.subpart": "No sub-element were found for this element !",
|
||||
"error.content.data.part.unknown": "Unknown element: \"%s\" !",
|
||||
|
||||
"content.title.error": "Error",
|
||||
"content.title.content": "Content",
|
||||
@@ -118,6 +122,18 @@
|
||||
"content.search.count.single": "result",
|
||||
"content.search.count.multiple": "results",
|
||||
|
||||
"content.commons.version.current": "Current version",
|
||||
"content.commons.version.previous.single": "Previous version",
|
||||
"content.commons.version.previous.multiple": "Previous versions",
|
||||
"content.commons.version.old.single": "Old version",
|
||||
"content.commons.version.old.multiple": "Old versions",
|
||||
"content.commons.cpu": "CPU Architecture",
|
||||
"content.commons.cpu.x64": "x64",
|
||||
"content.commons.cpu.x86": "x86",
|
||||
"content.commons.lang": "Language",
|
||||
"content.commons.download.single": "Download",
|
||||
"content.commons.download.multiple": "Downloads",
|
||||
|
||||
"about.biography.title": "Who am I ?",
|
||||
"about.philosophy.title": "Projects philosophy",
|
||||
"about.skills.title": "Skills",
|
||||
@@ -235,8 +251,12 @@
|
||||
"error.content.tags.alphanumeric": "Un des tags donné dans le paramètre d'URL \"tags\" n'est pas une chaîne de texte alphanumérique valide.",
|
||||
"error.content.detect.type": "Le type de contenu désiré n'as pas pu être détecté.",
|
||||
"error.content.id.alphanumeric": "L'ID de la ressource demandée n'est pas valide.",
|
||||
"error.content.data.not.exist": "La ressource demandée n'a pas de fichier de données associé.",
|
||||
"error.content.data.not.exist": "Le contenu demandée n'a pas de fichier de données interne associé.",
|
||||
"error.content.data.no.title": "Aucun titre trouvé !",
|
||||
"error.content.data.no.tags": "Aucun tag trouvé !",
|
||||
"error.content.data.no.parts": "Aucun élément à présenter n'a été trouvé !",
|
||||
"error.content.data.no.subpart": "Aucun sous-élément n'a été trouvé pour cet élément !",
|
||||
"error.content.data.part.unknown": "Élément inconnu: \"%s\" !",
|
||||
|
||||
"content.title.error": "Erreur de contenu",
|
||||
"content.title.content": "Content",
|
||||
@@ -247,6 +267,18 @@
|
||||
"content.search.count.single": "résultat",
|
||||
"content.search.count.multiple": "résultats",
|
||||
|
||||
"content.commons.version.current": "Version actuelle",
|
||||
"content.commons.version.previous.single": "Version précédente",
|
||||
"content.commons.version.previous.multiple": "Versions précédentes",
|
||||
"content.commons.version.old.single": "Ancienne version",
|
||||
"content.commons.version.old.multiple": "Anciennes versions",
|
||||
"content.commons.cpu": "Architecture de CPU",
|
||||
"content.commons.cpu.x64": "x64",
|
||||
"content.commons.cpu.x86": "x86",
|
||||
"content.commons.lang": "Langue",
|
||||
"content.commons.download.single": "Téléchargement",
|
||||
"content.commons.download.multiple": "Téléchargements",
|
||||
|
||||
"about.biography.title": "Qui suis-je ?",
|
||||
"about.philosophy.title": "Philosophie des projets",
|
||||
"about.skills.title": "Compétences",
|
||||
|
@@ -1,47 +1,47 @@
|
||||
[
|
||||
{
|
||||
"id": "test01",
|
||||
"title": {
|
||||
"en": "Test article",
|
||||
"fr": "Article de test"
|
||||
},
|
||||
"preamble": {
|
||||
"en": "This is a test article, please ignore it",
|
||||
"fr": "Ceci est un article de test, veuillez l'ignorer."
|
||||
},
|
||||
"image": "/resources/Azias/imgs/angry-alchool-pussy.png",
|
||||
"tags": [
|
||||
"test", "programming", "purebasic"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "test02",
|
||||
"title": {
|
||||
"en": "Test article #2",
|
||||
"fr": "Article de test #2"
|
||||
},
|
||||
"preamble": {
|
||||
"en": "This is a test article, please ignore it",
|
||||
"fr": "Ceci est un article de test, veuillez l'ignorer."
|
||||
},
|
||||
"image": "test.jpg",
|
||||
"tags": [
|
||||
"test", "programming", "docker"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "lscom-cli",
|
||||
"title": {
|
||||
"en": "PB-ListComPort - CLI COM port enumerator",
|
||||
"fr": "PB-ListComPort - Enumérateur de port COM pour invité de commande"
|
||||
"en": "PB-ListComPort",
|
||||
"fr": "PB-ListComPort"
|
||||
},
|
||||
"preamble": {
|
||||
"en": "A simple tool that can list COM ports with their name, friendly name and device name easily and cleanly.<br>This tool is intended to replace the tedious task of having to use the <code>mode</code> command, and the <i>Device Manager</i> to find a newly plugged-in device that provides a COM port.",
|
||||
"en": "A simple CLI tool that can list COM ports with their name, friendly name and device name easily and cleanly.<br>This tool is intended to replace the tedious task of having to use the <code>mode</code> command, and the <i>Device Manager</i> to find a newly plugged-in device that provides a COM port.",
|
||||
"fr": "..."
|
||||
},
|
||||
"image": "/resources/Azias/imgs/lscom-v2-text-01-bkgd-cli.png",
|
||||
"tags": [
|
||||
"application", "lscom", "purebasic", "windows"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "youtube-auto-archiver",
|
||||
"title": {
|
||||
"en": "Youtube-Auto-Archiver",
|
||||
"fr": "Youtube-Auto-Archiver"
|
||||
},
|
||||
"preamble": {
|
||||
"en": "...",
|
||||
"fr": "..."
|
||||
},
|
||||
"image": "/resources/Azias/imgs/placeholder.jpg",
|
||||
"tags": [
|
||||
"docker", "web", "python"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "excel-worksheet-password-remover",
|
||||
"title": {
|
||||
"en": "Excel-Worksheet-Password-Remover",
|
||||
"fr": "Excel-Worksheet-Password-Remover"
|
||||
},
|
||||
"preamble": {
|
||||
"en": "Small web page from which you can easily remove a password from an Excel worksheet without uploading any file, directly in your browser.<br>It works by leaving the task of editing the XML files on an Excel document to your browser instead to keep everything local.",
|
||||
"fr": "Petite application web qui permet de facilement retirer le mot de passe d'une feuille de calcul Excel depuis votre navigateur web sans avoir à uploader le fichier sur internet.<br>Cette application laisse votre navigateur modifier les fichiers XML du fichier Excel afin de tout garder en local."
|
||||
},
|
||||
"image": "/resources/Azias/imgs/excel-password-remover.png",
|
||||
"tags": [
|
||||
"tool", "web"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
@@ -8,11 +8,8 @@ include_once 'content.php';
|
||||
// Checking if an error occurred while loading data and parsing the URL.
|
||||
$content_error_code = 200;
|
||||
if($content_has_error) {
|
||||
if(is_null($requested_tags)) {
|
||||
// Failed to parse URL and detect a default category.
|
||||
header("HTTP/1.1 400 Bad Request");
|
||||
$content_error_code = 400;
|
||||
} elseif(is_null($filtered_content_index_data)) {
|
||||
// TODO: Add condition for the lack of data for an item.
|
||||
if(is_null($filtered_content_index_data)) {
|
||||
// Failed to get a display type or to extract types.
|
||||
header("HTTP/1.1 400 Bad Request");
|
||||
$content_error_code = 400;
|
||||
@@ -35,6 +32,7 @@ if($content_has_error) {
|
||||
<meta property="og:image" content="<?php echo($host_uri); ?>/resources/Azias/logos/rect1750-9-7-3-shaded.png"/>
|
||||
<meta property="og:image:type" content="image/png"/>
|
||||
<meta property="og:description" content="???"/>
|
||||
<link href="/resources/GliderJs/1.7.6/glider.min.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body class="with-custom-webkit-scrollbars with-custom-css-scrollbars dark-mode" data-dm-shortcut-enabled="true" data-sidebar-shortcut-enabled="true">
|
||||
<?php include 'body-root.php'; ?>
|
||||
@@ -56,7 +54,15 @@ if($content_has_error) {
|
||||
} elseif($requested_content_display_type == ContentDisplayType::SEARCH) {
|
||||
echo(localize("content.title.content").'<span class="mx-10">❱</span>'.localize("content.title.search"));
|
||||
} elseif($requested_content_display_type == ContentDisplayType::CONTENT) {
|
||||
echo(localize("content.title.content").'<span class="mx-10">❱</span>$TODO');
|
||||
$_nav_title_text = '<i>' . localize("error.content.data.no.title") . '</i>';
|
||||
if (array_key_exists("page", $requested_item_data["title"])) {
|
||||
if (array_key_exists($user_language, $requested_item_data["title"]["page"])) {
|
||||
$_nav_title_text = $requested_item_data["title"]["page"][$user_language];
|
||||
} elseif (array_key_exists($default_language, $requested_item_data["title"]["page"])) {
|
||||
$_nav_title_text = $requested_item_data["title"]["page"][$user_language];
|
||||
}
|
||||
}
|
||||
echo(localize("content.title.content").'<span class="mx-10">❱</span>'.$_nav_title_text);
|
||||
}
|
||||
?>
|
||||
</h2>
|
||||
@@ -74,6 +80,9 @@ if($content_has_error) {
|
||||
endMainCard();
|
||||
|
||||
if($SHOW_CONTENT_DEBUG_CARD) {
|
||||
// ################
|
||||
// Debugging card
|
||||
// ################
|
||||
echo('<div class="card p-0 mx-0">
|
||||
<div class="px-card py-10 border-bottom px-20">
|
||||
<div class="container-fluid">
|
||||
@@ -108,12 +117,15 @@ if($content_has_error) {
|
||||
|
||||
// Checking if an error occurred.
|
||||
if($content_error_code != 200) {
|
||||
// #############
|
||||
// Error card
|
||||
// #############
|
||||
startMainCard("fad fa-exclamation-triangle", localize('error.content.title.generic'), "");
|
||||
echo('<div class="py-20 bg-light-lm rounded-bottom px-0 bg-very-dark title-bkgd">');
|
||||
echo('<h3 class="m-0 font-size-20 text-center font-weight-semi-bold">'.$content_error_message.'</h3>');
|
||||
echo('</div>');
|
||||
echo('<div class="px-card py-10 bg-light-lm bg-dark-dm rounded-bottom border-top">'.
|
||||
'<p class="font-size-12 m-0">'.
|
||||
'<p class="font-size-12 m-0 text-super-muted">'.
|
||||
'Card footer here.'.
|
||||
'</p></div>');
|
||||
endMainCard();
|
||||
@@ -122,6 +134,10 @@ if($content_has_error) {
|
||||
|
||||
// Printing the containers
|
||||
if($requested_content_display_type == ContentDisplayType::SEARCH) {
|
||||
// #############
|
||||
// Search page
|
||||
// #############
|
||||
|
||||
// Creating the start of the card, only a "</div>" should be required afterward.
|
||||
startMainCard(
|
||||
"fad fa-file-search",
|
||||
@@ -154,7 +170,8 @@ if($content_has_error) {
|
||||
echo('<div class="content-tag-container">');
|
||||
echo('<i class="fad fa-tags"></i>');
|
||||
for($j = 0; $j < count($filtered_content_index_data[$i]["tags"]); $j++) {
|
||||
echo('<a href="#" class="content-tag">#'.$filtered_content_index_data[$i]["tags"][$j].'</a>');
|
||||
echo('<a href="'.l10n_url_abs("/content/?tags=".$filtered_content_index_data[$i]["tags"][$j]).'" class="content-tag">#');
|
||||
echo($filtered_content_index_data[$i]["tags"][$j].'</a>');
|
||||
}
|
||||
echo('</div>');
|
||||
echo('</div>');
|
||||
@@ -163,38 +180,88 @@ if($content_has_error) {
|
||||
}
|
||||
echo('</div>');
|
||||
echo('<div class="px-card py-10 bg-light-lm bg-dark-dm rounded-bottom border-top">'.
|
||||
'<p class="font-size-12 m-0">'.
|
||||
'<p class="font-size-12 m-0 text-super-muted">'.
|
||||
'Card footer here.'.
|
||||
'</p></div>');
|
||||
endMainCard();
|
||||
} elseif($requested_content_display_type == ContentDisplayType::CONTENT) {
|
||||
$_title_icon = "fad fa-question";
|
||||
$_title_text = '<i>' . localize("error.content.data.no.title") . '</i>';
|
||||
// ##############
|
||||
// Content page
|
||||
// ##############
|
||||
|
||||
// Preparing soma variables for the icon, title and subtitle.
|
||||
$_title_icon = "fad fa-question";
|
||||
$_title_text_main = '<i>'.localize("error.content.data.no.title").'</i>';
|
||||
$_title_text_sub = NULL;
|
||||
|
||||
// Attempting to read the card's icon, title and subtitle.
|
||||
if (array_key_exists("title", $requested_item_data)) {
|
||||
if (array_key_exists("icon", $requested_item_data["title"])) {
|
||||
$_title_icon = $requested_item_data["title"]["icon"];
|
||||
}
|
||||
|
||||
if (array_key_exists($user_language, $requested_item_data["title"])) {
|
||||
$_title_text = $requested_item_data["title"][$user_language];
|
||||
} elseif (array_key_exists($default_language, $requested_item_data["title"])) {
|
||||
$_title_text = $requested_item_data["title"][$user_language];
|
||||
if (array_key_exists("card", $requested_item_data["title"])) {
|
||||
if (array_key_exists("main", $requested_item_data["title"]["card"])) {
|
||||
$_title_text_main = getContentItemText($requested_item_data["title"]["card"]["main"], true);
|
||||
}
|
||||
if (array_key_exists("sub", $requested_item_data["title"]["card"])) {
|
||||
$_title_text_sub = getContentItemText($requested_item_data["title"]["card"]["sub"], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
startMainCard($_title_icon, $_title_text, "");
|
||||
// Opening the card.
|
||||
startMainCard($_title_icon, $_title_text_main, (is_null($_title_text_sub) ? "" : $_title_text_sub));
|
||||
|
||||
// Opening the content container.
|
||||
echo('<div class="py-20 bg-light-lm rounded-bottom px-0 bg-very-dark title-bkgd">');
|
||||
echo('<div class="content m-0 mx-20">');
|
||||
|
||||
// Adding elements defined in the JSON file.
|
||||
if(array_key_exists("parts", $requested_item_data)) {
|
||||
for ($i = 0; $i < count($requested_item_data["parts"]); $i++) {
|
||||
createElementNode($requested_item_data["parts"][$i]);
|
||||
}
|
||||
} else {
|
||||
echo('<h3 class="m-0 font-size-20 text-center text-danger font-weight-semi-bold">');
|
||||
echo(localize("error.content.data.no.parts").'</h3>');
|
||||
}
|
||||
|
||||
// New elements test zone. - START
|
||||
|
||||
/*echo('<div class="content m-0 mx-20">');
|
||||
echo('<p class="my-0">Text will go here...</p>');
|
||||
echo('</div>');
|
||||
|
||||
echo('<div class="sidebar-divider m-20 mx-0"></div>');/**/
|
||||
//echo('<hr class="subtle">');
|
||||
|
||||
/*<td>
|
||||
<a href="#" class="d-flex justify-content-center align-items-center">
|
||||
<p class="m-0 p-0 text-monospace">lscom_fra_x86.exe</p>
|
||||
<button class="btn btn-sm btn-success font-size-18 px-5 ml-15" type="button">
|
||||
<i class="fad fa-save"></i>
|
||||
</button>
|
||||
</a>
|
||||
</td>*/
|
||||
|
||||
// New elements test zone. - END
|
||||
|
||||
// Closing the content container.
|
||||
echo('</div>');
|
||||
|
||||
echo('<div class="px-card py-10 bg-light-lm bg-dark-dm rounded-bottom border-top">' .
|
||||
'<p class="font-size-12 m-0">' .
|
||||
'Card footer here.' .
|
||||
'</p></div>');
|
||||
// Printing the tags' section at the end of the card
|
||||
echo('<div class="px-20 py-10 bg-light-lm bg-dark-dm rounded-bottom border-top">');
|
||||
echo('<div class="content-tag-container"><i class="fad fa-tags"></i>');
|
||||
if(array_key_exists("tags", $requested_item_data)) {
|
||||
for($i = 0; $i < count($requested_item_data["tags"]); $i++) {
|
||||
echo('<a href="'.l10n_url_abs("/content/?tags=".$requested_item_data["tags"][$i]).'" class="content-tag">#');
|
||||
echo($requested_item_data["tags"][$i].'</a>');
|
||||
}
|
||||
} else {
|
||||
echo('<i>'.localize("error.content.data.no.tags").'</i>');
|
||||
}
|
||||
echo('</div></div>');
|
||||
|
||||
// Closing the card.
|
||||
endMainCard();
|
||||
}
|
||||
|
||||
@@ -206,6 +273,7 @@ if($content_has_error) {
|
||||
<?php include 'footer.php'; ?>
|
||||
</div>
|
||||
<script src="/resources/HalfMoon/1.1.1/js/halfmoon.min.js"></script>
|
||||
<script src="/resources/GliderJs/1.7.6/glider-compat.min.js"></script>
|
||||
<script src="/resources/Azias/js/nibblepoker.lu.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -1,13 +1,100 @@
|
||||
{
|
||||
"title": {
|
||||
"icon": "fad fa-terminal",
|
||||
"en": "PB-ListComPort - CLI COM port enumerator",
|
||||
"fr": "PB-ListComPort - Enumérateur de port COM pour invité de commande"
|
||||
"page": {
|
||||
"en": "PB-ListComPort",
|
||||
"fr": "PB-ListComPort"
|
||||
},
|
||||
"tags": [
|
||||
"programming", "lscom"
|
||||
"card": {
|
||||
"main": {
|
||||
"en": "PB-ListComPort",
|
||||
"fr": "PB-ListComPort"
|
||||
},
|
||||
"sub": {
|
||||
"en": "CLI COM port enumerator",
|
||||
"fr": "Enumérateur de port COM pour invité de commande"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parts": [
|
||||
{
|
||||
"type": "collapse",
|
||||
"title": {
|
||||
"key": "content.commons.version.current"
|
||||
},
|
||||
"subtitle": {
|
||||
"en": "v2.1.0",
|
||||
"fr": "v2.1.0"
|
||||
},
|
||||
"modifiers": [
|
||||
"no-rounding",
|
||||
"no-padding-content"
|
||||
],
|
||||
"toggles": {
|
||||
"downloads": true
|
||||
"parts": [
|
||||
{
|
||||
"type": "table",
|
||||
"modifiers": [
|
||||
"striped",
|
||||
"inner-bordered"
|
||||
],
|
||||
"head": [
|
||||
{
|
||||
"key": "content.commons.cpu"
|
||||
},
|
||||
{
|
||||
"key": "content.commons.lang"
|
||||
},
|
||||
{
|
||||
"key": "content.commons.download.single"
|
||||
}
|
||||
],
|
||||
"body": [
|
||||
[
|
||||
{
|
||||
"key": "content.commons.cpu.x64",
|
||||
"rowspan": 2
|
||||
},
|
||||
{
|
||||
"key": "lang.english"
|
||||
},
|
||||
{
|
||||
"en": "URL here"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"key": "lang.french"
|
||||
},
|
||||
{
|
||||
"en": "URL here"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"key": "content.commons.cpu.x86",
|
||||
"rowspan": 2
|
||||
},
|
||||
{
|
||||
"key": "lang.english"
|
||||
},
|
||||
{
|
||||
"en": "URL here"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"key": "lang.french"
|
||||
},
|
||||
{
|
||||
"en": "URL here"
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"application", "lscom", "purebasic", "windows"
|
||||
]
|
||||
}
|
||||
|
@@ -4,11 +4,6 @@
|
||||
src: url("/resources/Quantum/Quantum.otf") format('opentype');
|
||||
}
|
||||
|
||||
/* Preventing images from being saved with the right-click */
|
||||
img.no-save {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Background for the main container and its cards */
|
||||
div#body-overlay {
|
||||
position: absolute;
|
||||
@@ -28,13 +23,11 @@ div#body-overlay {
|
||||
background-image: url("/resources/Azias/imgs/3px-tile-0.1.png");
|
||||
}
|
||||
|
||||
/* Helpers */
|
||||
/* Utilities, helpers & misc */
|
||||
img.no-save {
|
||||
pointer-events: none;
|
||||
}
|
||||
.no-select {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.quantum {
|
||||
@@ -59,7 +52,6 @@ div#body-overlay {
|
||||
font-size: 3.0rem!important;
|
||||
}
|
||||
.text-super-muted {
|
||||
/*color: #6E6E6E;/**/
|
||||
color: #89898A;
|
||||
}
|
||||
.square-corners {
|
||||
@@ -68,6 +60,10 @@ div#body-overlay {
|
||||
.stretch-align-items {
|
||||
align-items: stretch;
|
||||
}
|
||||
.py-01 {
|
||||
padding-top: 0.01rem!important;
|
||||
padding-bottom: 0.01rem!important;
|
||||
}
|
||||
|
||||
/* Unique rules */
|
||||
#copyright-text {
|
||||
@@ -101,7 +97,6 @@ div#body-overlay {
|
||||
filter: invert(100%);
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
hr, hr.dark-mde, hr.subtle {
|
||||
background-color: rgba(0, 0, 0, 0) !important;
|
||||
background: rgb(93,95,97);
|
||||
@@ -111,7 +106,8 @@ hr, hr.dark-mde, hr.subtle {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
/* Content search */
|
||||
/* Content */
|
||||
/* Content > Search */
|
||||
@media (max-width: 992px) {
|
||||
:root {
|
||||
--content-search-image-size: 96px;
|
||||
@@ -161,6 +157,7 @@ div.content-tag-container a:not(:first-child) {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
/* Gradient used on home page's applications card */
|
||||
@media (min-width: 993px) {
|
||||
.l-lab-web {
|
||||
background: linear-gradient(90deg, rgba(101,144,134,0.3) 0%, rgba(101,144,134,0.2) 1.5px, rgba(101,144,134,0.0) 7px);
|
||||
@@ -176,7 +173,7 @@ div.content-tag-container a:not(:first-child) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom dynamic sizing */
|
||||
/* Custom dynamic sizing for main containers in primary ".content-wrapper" */
|
||||
.w-lg-p90 {
|
||||
width: 95% !important;
|
||||
}
|
||||
@@ -192,26 +189,16 @@ div.content-tag-container a:not(:first-child) {
|
||||
}
|
||||
|
||||
/* Fixes */
|
||||
/* TODO: Fix it when it is closed */
|
||||
/* No idea where this is used */
|
||||
div.last-inner-collapse-border-fix {
|
||||
/* TODO: Fix it when it is closed */
|
||||
border: var(--collapse-content-border-width) solid var(--dm-collapse-content-border-color) !important;
|
||||
border-top: 0 !important;
|
||||
border-bottom-left-radius: var(--collapse-content-border-radius) !important;
|
||||
border-bottom-right-radius: var(--collapse-content-border-radius) !important;
|
||||
}
|
||||
|
||||
|
||||
/* Trash */
|
||||
/*.lang-icon {
|
||||
height: var(--base-line-height);
|
||||
max-height: var(--base-line-height);
|
||||
height: var(--base-font-size);
|
||||
max-height: var(--base-font-size);
|
||||
}*/
|
||||
/*.page-wrapper.with-transitions.with-sidebar .content-wrapper {
|
||||
transition: none;
|
||||
}/**/
|
||||
/*div#body-overlay.error {
|
||||
background-image: url("/resources/Azias/imgs/psychedelic.png");
|
||||
opacity: 0.075;
|
||||
}/**/
|
||||
/* Fix for ".content-wrapper" on mobile which can be too large due to the main title */
|
||||
.content-wrapper {
|
||||
max-width: 100vw;
|
||||
}
|
||||
|
BIN
resources/Azias/imgs/excel-password-remover.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
resources/Azias/imgs/lscom/screen-cli-csv-2x-xBR.png
Normal file
After Width: | Height: | Size: 66 KiB |
BIN
resources/Azias/imgs/lscom/screen-cli-csv-2x.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
resources/Azias/imgs/lscom/screen-cli-csv.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
resources/Azias/imgs/lscom/screen-cli-full-2x-xBR.png
Normal file
After Width: | Height: | Size: 66 KiB |
BIN
resources/Azias/imgs/lscom/screen-cli-full-2x.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
resources/Azias/imgs/lscom/screen-cli-full.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
resources/Azias/imgs/lscom/screen-cli-stylish-2x-xBR.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
resources/Azias/imgs/lscom/screen-cli-stylish-2x.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
resources/Azias/imgs/lscom/screen-cli-stylish.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
5
resources/GliderJs/1.7.6/LICENSE.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
11
resources/GliderJs/1.7.6/glider-compat.min.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
"document"in self&&("classList"in document.createElement("_")&&(!document.createElementNS||"classList"in document.createElementNS("http://www.w3.org/2000/svg","g"))||!function(b){if("Element"in b){b=b.Element.prototype;var d=Object,g=String.prototype.trim||function(){return this.replace(/^\s+|\s+$/g,"")},a=Array.prototype.indexOf||function(l){for(var f=0,a=this.length;a>f;f++)if(f in this&&this[f]===l)return f;return-1},c=function(a,f){this.name=a;this.code=DOMException[a];this.message=f},h=function(l,
|
||||
f){if(""===f)throw new c("SYNTAX_ERR","The token must not be empty.");if(/\s/.test(f))throw new c("INVALID_CHARACTER_ERR","The token must not contain space characters.");return a.call(l,f)},k=function(a){var f=g.call(a.getAttribute("class")||"");f=f?f.split(/\s+/):[];for(var b=0,h=f.length;h>b;b++)this.push(f[b]);this._updateClassName=function(){a.setAttribute("class",this.toString())}},e=k.prototype=[],m=function(){return new k(this)};if(c.prototype=Error.prototype,e.item=function(a){return this[a]||
|
||||
null},e.contains=function(a){return~h(this,a+"")},e.add=function(){var a=arguments,f=0,b=a.length,c=!1;do{var e=a[f]+"";~h(this,e)||(this.push(e),c=!0)}while(++f<b);c&&this._updateClassName()},e.remove=function(){var a,b=arguments,c=0,e=b.length,k=!1;do{var d=b[c]+"";for(a=h(this,d);~a;)this.splice(a,1),k=!0,a=h(this,d)}while(++c<e);k&&this._updateClassName()},e.toggle=function(a,b){var h=this.contains(a),c=h?!0!==b&&"remove":!1!==b&&"add";return c&&this[c](a),!0===b||!1===b?b:!h},e.replace=function(a,
|
||||
b){var c=h(a+"");~c&&(this.splice(c,1,b),this._updateClassName())},e.toString=function(){return this.join(" ")},d.defineProperty){e={get:m,enumerable:!0,configurable:!0};try{d.defineProperty(b,"classList",e)}catch(l){void 0!==l.number&&-2146823252!==l.number||(e.enumerable=!1,d.defineProperty(b,"classList",e))}}else d.prototype.__defineGetter__&&b.__defineGetter__("classList",m)}}(self),function(){var b=document.createElement("_");if(b.classList.add("c1","c2"),!b.classList.contains("c2")){var d=function(a){var b=
|
||||
DOMTokenList.prototype[a];DOMTokenList.prototype[a]=function(a){var c,h=arguments.length;for(c=0;h>c;c++)a=arguments[c],b.call(this,a)}};d("add");d("remove")}if(b.classList.toggle("c3",!1),b.classList.contains("c3")){var g=DOMTokenList.prototype.toggle;DOMTokenList.prototype.toggle=function(a,b){return 1 in arguments&&!this.contains(a)==!b?b:g.call(this,a)}}"replace"in document.createElement("_").classList||(DOMTokenList.prototype.replace=function(a,b){var c=this.toString().split(" "),d=c.indexOf(a+
|
||||
"");~d&&(c=c.slice(d),this.remove.apply(this,c),this.add(b),this.add.apply(this,c.slice(1)))});b=null}());
|
||||
(function(){if("undefined"!==typeof window)try{var b=new window.CustomEvent("test",{cancelable:!0});b.preventDefault();if(!0!==b.defaultPrevented)throw Error("Could not prevent default");}catch(d){b=function(b,a){a=a||{bubbles:!1,cancelable:!1,detail:void 0};var c=document.createEvent("CustomEvent");c.initCustomEvent(b,a.bubbles,a.cancelable,a.detail);var d=c.preventDefault;c.preventDefault=function(){d.call(this);try{Object.defineProperty(this,"defaultPrevented",{get:function(){return!0}})}catch(k){this.defaultPrevented=
|
||||
!0}};return c},b.prototype=window.Event.prototype,window.CustomEvent=b}})();
|
||||
Object.assign||Object.defineProperty(Object,"assign",{enumerable:!1,configurable:!0,writable:!0,value:function(b){if(void 0===b||null===b)throw new TypeError("Cannot convert first argument to object");for(var d=Object(b),g=1;g<arguments.length;g++){var a=arguments[g];if(void 0!==a&&null!==a){a=Object(a);for(var c=Object.keys(Object(a)),h=0,k=c.length;h<k;h++){var e=c[h],m=Object.getOwnPropertyDescriptor(a,e);void 0!==m&&m.enumerable&&(d[e]=a[e])}}}return d}});
|
||||
(function(){for(var b=0,d=["ms","moz","webkit","o"],g=0;g<d.length&&!window.requestAnimationFrame;++g)window.requestAnimationFrame=window[d[g]+"RequestAnimationFrame"],window.cancelAnimationFrame=window[d[g]+"CancelAnimationFrame"]||window[d[g]+"CancelRequestAnimationFrame"];window.requestAnimationFrame||(window.requestAnimationFrame=function(a,c){var d=(new Date).getTime(),g=Math.max(0,16-(d-b)),e=window.setTimeout(function(){a(d+g)},g);b=d+g;return e});window.cancelAnimationFrame||(window.cancelAnimationFrame=
|
||||
function(a){clearTimeout(a)})})();
|
129
resources/GliderJs/1.7.6/glider.css
Normal file
@@ -0,0 +1,129 @@
|
||||
.glider-contain {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
}
|
||||
.glider {
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
overflow-y: hidden;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
-ms-overflow-style: none;
|
||||
transform: translateZ(0);
|
||||
}
|
||||
.glider-track {
|
||||
transform: translateZ(0);
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
z-index: 1;
|
||||
}
|
||||
.glider.draggable {
|
||||
user-select: none;
|
||||
cursor: -webkit-grab;
|
||||
cursor: grab;
|
||||
}
|
||||
.glider.draggable .glider-slide img {
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
.glider.drag {
|
||||
cursor: -webkit-grabbing;
|
||||
cursor: grabbing;
|
||||
}
|
||||
.glider-slide {
|
||||
user-select: none;
|
||||
justify-content: center;
|
||||
align-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
.glider-slide img {
|
||||
max-width: 100%;
|
||||
}
|
||||
.glider::-webkit-scrollbar {
|
||||
opacity: 0;
|
||||
height: 0;
|
||||
}
|
||||
.glider-prev,.glider-next {
|
||||
user-select: none;
|
||||
position: absolute;
|
||||
outline: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
z-index: 2;
|
||||
font-size: 40px;
|
||||
text-decoration: none;
|
||||
left: -23px;
|
||||
border: 0;
|
||||
top: 30%;
|
||||
cursor: pointer;
|
||||
color: #666;
|
||||
opacity: 1;
|
||||
line-height: 1;
|
||||
transition: opacity .5s cubic-bezier(.17,.67,.83,.67),
|
||||
color .5s cubic-bezier(.17,.67,.83,.67);
|
||||
}
|
||||
.glider-prev:hover,
|
||||
.glider-next:hover,
|
||||
.glider-prev:focus,
|
||||
.glider-next:focus {
|
||||
color: #a89cc8;
|
||||
}
|
||||
.glider-next {
|
||||
right: -23px;
|
||||
left: auto;
|
||||
}
|
||||
.glider-next.disabled,
|
||||
.glider-prev.disabled {
|
||||
opacity: .25;
|
||||
color: #666;
|
||||
cursor: default;
|
||||
}
|
||||
.glider-slide {
|
||||
min-width: 150px;
|
||||
}
|
||||
.glider-hide {
|
||||
opacity: 0;
|
||||
}
|
||||
.glider-dots {
|
||||
user-select: none;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
}
|
||||
.glider-dot {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
user-select: none;
|
||||
outline: none;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
color: #ccc;
|
||||
border-radius: 999px;
|
||||
background: #ccc;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
margin: 7px;
|
||||
}
|
||||
.glider-dot:hover,
|
||||
.glider-dot:focus,
|
||||
.glider-dot.active {
|
||||
background: #a89cc8;
|
||||
}
|
||||
@media(max-width: 36em){
|
||||
.glider::-webkit-scrollbar {
|
||||
opacity: 1;
|
||||
-webkit-appearance: none;
|
||||
width: 7px;
|
||||
height: 3px;
|
||||
}
|
||||
.glider::-webkit-scrollbar-thumb {
|
||||
opacity: 1;
|
||||
border-radius: 99px;
|
||||
background-color: rgba(156, 156, 156, 0.25);
|
||||
box-shadow: 0 0 1px rgba(255,255,255,.25);
|
||||
}
|
||||
}
|
576
resources/GliderJs/1.7.6/glider.js
Normal file
@@ -0,0 +1,576 @@
|
||||
/* @preserve
|
||||
_____ __ _ __ _
|
||||
/ ___// /(_)___/ /___ ____ (_)___
|
||||
/ (_ // // // _ // -_)/ __/_ / /(_-<
|
||||
\___//_//_/ \_,_/ \__//_/ (_)__/ //___/
|
||||
|___/
|
||||
|
||||
Version: 1.7.4
|
||||
Author: Nick Piscitelli (pickykneee)
|
||||
Website: https://nickpiscitelli.com
|
||||
Documentation: http://nickpiscitelli.github.io/Glider.js
|
||||
License: MIT License
|
||||
Release Date: October 25th, 2018
|
||||
|
||||
*/
|
||||
|
||||
/* global define */
|
||||
|
||||
(function (factory) {
|
||||
typeof define === 'function' && define.amd
|
||||
? define(factory)
|
||||
: typeof exports === 'object'
|
||||
? (module.exports = factory())
|
||||
: factory()
|
||||
})(function () {
|
||||
('use strict') // eslint-disable-line no-unused-expressions
|
||||
|
||||
/* globals window:true */
|
||||
var _window = typeof window !== 'undefined' ? window : this
|
||||
|
||||
var Glider = (_window.Glider = function (element, settings) {
|
||||
var _ = this
|
||||
|
||||
if (element._glider) return element._glider
|
||||
|
||||
_.ele = element
|
||||
_.ele.classList.add('glider')
|
||||
|
||||
// expose glider object to its DOM element
|
||||
_.ele._glider = _
|
||||
|
||||
// merge user setting with defaults
|
||||
_.opt = Object.assign(
|
||||
{},
|
||||
{
|
||||
slidesToScroll: 1,
|
||||
slidesToShow: 1,
|
||||
resizeLock: true,
|
||||
duration: 0.5,
|
||||
// easeInQuad
|
||||
easing: function (x, t, b, c, d) {
|
||||
return c * (t /= d) * t + b
|
||||
}
|
||||
},
|
||||
settings
|
||||
)
|
||||
|
||||
// set defaults
|
||||
_.animate_id = _.page = _.slide = _.scrollLeft = 0
|
||||
_.arrows = {}
|
||||
|
||||
// preserve original options to
|
||||
// extend breakpoint settings
|
||||
_._opt = _.opt
|
||||
|
||||
if (_.opt.skipTrack) {
|
||||
// first and only child is the track
|
||||
_.track = _.ele.children[0]
|
||||
} else {
|
||||
// create track and wrap slides
|
||||
_.track = document.createElement('div')
|
||||
_.ele.appendChild(_.track)
|
||||
while (_.ele.children.length !== 1) {
|
||||
_.track.appendChild(_.ele.children[0])
|
||||
}
|
||||
}
|
||||
|
||||
_.track.classList.add('glider-track')
|
||||
|
||||
// start glider
|
||||
_.init()
|
||||
|
||||
// set events
|
||||
_.resize = _.init.bind(_, true)
|
||||
_.event(_.ele, 'add', {
|
||||
scroll: _.updateControls.bind(_)
|
||||
})
|
||||
_.event(_window, 'add', {
|
||||
resize: _.resize
|
||||
})
|
||||
})
|
||||
|
||||
var gliderPrototype = Glider.prototype
|
||||
gliderPrototype.init = function (refresh, paging) {
|
||||
var _ = this
|
||||
|
||||
var width = 0
|
||||
|
||||
var height = 0
|
||||
|
||||
_.slides = _.track.children;
|
||||
|
||||
[].forEach.call(_.slides, function (_, i) {
|
||||
_.classList.add('glider-slide')
|
||||
_.setAttribute('data-gslide', i)
|
||||
})
|
||||
|
||||
_.containerWidth = _.ele.clientWidth
|
||||
|
||||
var breakpointChanged = _.settingsBreakpoint()
|
||||
if (!paging) paging = breakpointChanged
|
||||
|
||||
if (
|
||||
_.opt.slidesToShow === 'auto' ||
|
||||
typeof _.opt._autoSlide !== 'undefined'
|
||||
) {
|
||||
var slideCount = _.containerWidth / _.opt.itemWidth
|
||||
|
||||
_.opt._autoSlide = _.opt.slidesToShow = _.opt.exactWidth
|
||||
? slideCount
|
||||
: Math.floor(slideCount)
|
||||
}
|
||||
if (_.opt.slidesToScroll === 'auto') {
|
||||
_.opt.slidesToScroll = Math.floor(_.opt.slidesToShow)
|
||||
}
|
||||
|
||||
_.itemWidth = _.opt.exactWidth
|
||||
? _.opt.itemWidth
|
||||
: _.containerWidth / _.opt.slidesToShow;
|
||||
|
||||
// set slide dimensions
|
||||
[].forEach.call(_.slides, function (__) {
|
||||
__.style.height = 'auto'
|
||||
__.style.width = _.itemWidth + 'px'
|
||||
width += _.itemWidth
|
||||
height = Math.max(__.offsetHeight, height)
|
||||
})
|
||||
|
||||
_.track.style.width = width + 'px'
|
||||
_.trackWidth = width
|
||||
_.isDrag = false
|
||||
_.preventClick = false
|
||||
|
||||
_.opt.resizeLock && _.scrollTo(_.slide * _.itemWidth, 0)
|
||||
|
||||
if (breakpointChanged || paging) {
|
||||
_.bindArrows()
|
||||
_.buildDots()
|
||||
_.bindDrag()
|
||||
}
|
||||
|
||||
_.updateControls()
|
||||
|
||||
_.emit(refresh ? 'refresh' : 'loaded')
|
||||
}
|
||||
|
||||
gliderPrototype.bindDrag = function () {
|
||||
var _ = this
|
||||
_.mouse = _.mouse || _.handleMouse.bind(_)
|
||||
|
||||
var mouseup = function () {
|
||||
_.mouseDown = undefined
|
||||
_.ele.classList.remove('drag')
|
||||
if (_.isDrag) {
|
||||
_.preventClick = true
|
||||
}
|
||||
_.isDrag = false
|
||||
}
|
||||
|
||||
var events = {
|
||||
mouseup: mouseup,
|
||||
mouseleave: mouseup,
|
||||
mousedown: function (e) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
_.mouseDown = e.clientX
|
||||
_.ele.classList.add('drag')
|
||||
},
|
||||
mousemove: _.mouse,
|
||||
click: function (e) {
|
||||
if (_.preventClick) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
}
|
||||
_.preventClick = false
|
||||
}
|
||||
}
|
||||
|
||||
_.ele.classList.toggle('draggable', _.opt.draggable === true)
|
||||
_.event(_.ele, 'remove', events)
|
||||
if (_.opt.draggable) _.event(_.ele, 'add', events)
|
||||
}
|
||||
|
||||
gliderPrototype.buildDots = function () {
|
||||
var _ = this
|
||||
|
||||
if (!_.opt.dots) {
|
||||
if (_.dots) _.dots.innerHTML = ''
|
||||
return
|
||||
}
|
||||
|
||||
if (typeof _.opt.dots === 'string') {
|
||||
_.dots = document.querySelector(_.opt.dots)
|
||||
} else _.dots = _.opt.dots
|
||||
if (!_.dots) return
|
||||
|
||||
_.dots.innerHTML = ''
|
||||
_.dots.classList.add('glider-dots')
|
||||
|
||||
for (var i = 0; i < Math.ceil(_.slides.length / _.opt.slidesToShow); ++i) {
|
||||
var dot = document.createElement('button')
|
||||
dot.dataset.index = i
|
||||
dot.setAttribute('aria-label', 'Page ' + (i + 1))
|
||||
dot.className = 'glider-dot ' + (i ? '' : 'active')
|
||||
_.event(dot, 'add', {
|
||||
click: _.scrollItem.bind(_, i, true)
|
||||
})
|
||||
_.dots.appendChild(dot)
|
||||
}
|
||||
}
|
||||
|
||||
gliderPrototype.bindArrows = function () {
|
||||
var _ = this
|
||||
if (!_.opt.arrows) {
|
||||
Object.keys(_.arrows).forEach(function (direction) {
|
||||
var element = _.arrows[direction]
|
||||
_.event(element, 'remove', { click: element._func })
|
||||
})
|
||||
return
|
||||
}
|
||||
['prev', 'next'].forEach(function (direction) {
|
||||
var arrow = _.opt.arrows[direction]
|
||||
if (arrow) {
|
||||
if (typeof arrow === 'string') arrow = document.querySelector(arrow)
|
||||
if (arrow) {
|
||||
arrow._func = arrow._func || _.scrollItem.bind(_, direction)
|
||||
_.event(arrow, 'remove', {
|
||||
click: arrow._func
|
||||
})
|
||||
_.event(arrow, 'add', {
|
||||
click: arrow._func
|
||||
})
|
||||
_.arrows[direction] = arrow
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
gliderPrototype.updateControls = function (event) {
|
||||
var _ = this
|
||||
|
||||
if (event && !_.opt.scrollPropagate) {
|
||||
event.stopPropagation()
|
||||
}
|
||||
|
||||
var disableArrows = _.containerWidth >= _.trackWidth
|
||||
|
||||
if (!_.opt.rewind) {
|
||||
if (_.arrows.prev) {
|
||||
_.arrows.prev.classList.toggle(
|
||||
'disabled',
|
||||
_.ele.scrollLeft <= 0 || disableArrows
|
||||
)
|
||||
_.arrows.prev.classList.contains('disabled')
|
||||
? _.arrows.prev.setAttribute('aria-disabled', true)
|
||||
: _.arrows.prev.setAttribute('aria-disabled', false)
|
||||
}
|
||||
if (_.arrows.next) {
|
||||
_.arrows.next.classList.toggle(
|
||||
'disabled',
|
||||
Math.ceil(_.scrollLeft + _.containerWidth) >=
|
||||
Math.floor(_.trackWidth) || disableArrows
|
||||
)
|
||||
_.arrows.next.classList.contains('disabled')
|
||||
? _.arrows.next.setAttribute('aria-disabled', true)
|
||||
: _.arrows.next.setAttribute('aria-disabled', false)
|
||||
}
|
||||
}
|
||||
|
||||
_.slide = Math.round(_.scrollLeft / _.itemWidth)
|
||||
_.page = Math.round(_.scrollLeft / _.containerWidth)
|
||||
|
||||
var middle = _.slide + Math.floor(Math.floor(_.opt.slidesToShow) / 2)
|
||||
|
||||
var extraMiddle = Math.floor(_.opt.slidesToShow) % 2 ? 0 : middle + 1
|
||||
if (Math.floor(_.opt.slidesToShow) === 1) {
|
||||
extraMiddle = 0
|
||||
}
|
||||
|
||||
// the last page may be less than one half of a normal page width so
|
||||
// the page is rounded down. when at the end, force the page to turn
|
||||
if (_.scrollLeft + _.containerWidth >= Math.floor(_.trackWidth)) {
|
||||
_.page = _.dots ? _.dots.children.length - 1 : 0
|
||||
}
|
||||
|
||||
[].forEach.call(_.slides, function (slide, index) {
|
||||
var slideClasses = slide.classList
|
||||
|
||||
var wasVisible = slideClasses.contains('visible')
|
||||
|
||||
var start = _.scrollLeft
|
||||
|
||||
var end = _.scrollLeft + _.containerWidth
|
||||
|
||||
var itemStart = _.itemWidth * index
|
||||
|
||||
var itemEnd = itemStart + _.itemWidth;
|
||||
|
||||
[].forEach.call(slideClasses, function (className) {
|
||||
/^left|right/.test(className) && slideClasses.remove(className)
|
||||
})
|
||||
slideClasses.toggle('active', _.slide === index)
|
||||
if (middle === index || (extraMiddle && extraMiddle === index)) {
|
||||
slideClasses.add('center')
|
||||
} else {
|
||||
slideClasses.remove('center')
|
||||
slideClasses.add(
|
||||
[
|
||||
index < middle ? 'left' : 'right',
|
||||
Math.abs(index - (index < middle ? middle : extraMiddle || middle))
|
||||
].join('-')
|
||||
)
|
||||
}
|
||||
|
||||
var isVisible =
|
||||
Math.ceil(itemStart) >= Math.floor(start) &&
|
||||
Math.floor(itemEnd) <= Math.ceil(end)
|
||||
slideClasses.toggle('visible', isVisible)
|
||||
if (isVisible !== wasVisible) {
|
||||
_.emit('slide-' + (isVisible ? 'visible' : 'hidden'), {
|
||||
slide: index
|
||||
})
|
||||
}
|
||||
})
|
||||
if (_.dots) {
|
||||
[].forEach.call(_.dots.children, function (dot, index) {
|
||||
dot.classList.toggle('active', _.page === index)
|
||||
})
|
||||
}
|
||||
|
||||
if (event && _.opt.scrollLock) {
|
||||
clearTimeout(_.scrollLock)
|
||||
_.scrollLock = setTimeout(function () {
|
||||
clearTimeout(_.scrollLock)
|
||||
// dont attempt to scroll less than a pixel fraction - causes looping
|
||||
if (Math.abs(_.ele.scrollLeft / _.itemWidth - _.slide) > 0.02) {
|
||||
if (!_.mouseDown) {
|
||||
// Only scroll if not at the end (#94)
|
||||
if (_.trackWidth > _.containerWidth + _.ele.scrollLeft) {
|
||||
_.scrollItem(_.getCurrentSlide())
|
||||
}
|
||||
}
|
||||
}
|
||||
}, _.opt.scrollLockDelay || 250)
|
||||
}
|
||||
}
|
||||
|
||||
gliderPrototype.getCurrentSlide = function () {
|
||||
var _ = this
|
||||
return _.round(_.ele.scrollLeft / _.itemWidth)
|
||||
}
|
||||
|
||||
gliderPrototype.scrollItem = function (slide, dot, e) {
|
||||
if (e) e.preventDefault()
|
||||
|
||||
var _ = this
|
||||
|
||||
var originalSlide = slide
|
||||
++_.animate_id
|
||||
|
||||
if (dot === true) {
|
||||
slide = slide * _.containerWidth
|
||||
slide = Math.round(slide / _.itemWidth) * _.itemWidth
|
||||
} else {
|
||||
if (typeof slide === 'string') {
|
||||
var backwards = slide === 'prev'
|
||||
|
||||
// use precise location if fractional slides are on
|
||||
if (_.opt.slidesToScroll % 1 || _.opt.slidesToShow % 1) {
|
||||
slide = _.getCurrentSlide()
|
||||
} else {
|
||||
slide = _.slide
|
||||
}
|
||||
|
||||
if (backwards) slide -= _.opt.slidesToScroll
|
||||
else slide += _.opt.slidesToScroll
|
||||
|
||||
if (_.opt.rewind) {
|
||||
var scrollLeft = _.ele.scrollLeft
|
||||
slide =
|
||||
backwards && !scrollLeft
|
||||
? _.slides.length
|
||||
: !backwards &&
|
||||
scrollLeft + _.containerWidth >= Math.floor(_.trackWidth)
|
||||
? 0
|
||||
: slide
|
||||
}
|
||||
}
|
||||
|
||||
slide = Math.max(Math.min(slide, _.slides.length), 0)
|
||||
|
||||
_.slide = slide
|
||||
slide = _.itemWidth * slide
|
||||
}
|
||||
|
||||
_.scrollTo(
|
||||
slide,
|
||||
_.opt.duration * Math.abs(_.ele.scrollLeft - slide),
|
||||
function () {
|
||||
_.updateControls()
|
||||
_.emit('animated', {
|
||||
value: originalSlide,
|
||||
type:
|
||||
typeof originalSlide === 'string' ? 'arrow' : dot ? 'dot' : 'slide'
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
gliderPrototype.settingsBreakpoint = function () {
|
||||
var _ = this
|
||||
|
||||
var resp = _._opt.responsive
|
||||
|
||||
if (resp) {
|
||||
// Sort the breakpoints in mobile first order
|
||||
resp.sort(function (a, b) {
|
||||
return b.breakpoint - a.breakpoint
|
||||
})
|
||||
|
||||
for (var i = 0; i < resp.length; ++i) {
|
||||
var size = resp[i]
|
||||
if (_window.innerWidth >= size.breakpoint) {
|
||||
if (_.breakpoint !== size.breakpoint) {
|
||||
_.opt = Object.assign({}, _._opt, size.settings)
|
||||
_.breakpoint = size.breakpoint
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
// set back to defaults in case they were overriden
|
||||
var breakpointChanged = _.breakpoint !== 0
|
||||
_.opt = Object.assign({}, _._opt)
|
||||
_.breakpoint = 0
|
||||
return breakpointChanged
|
||||
}
|
||||
|
||||
gliderPrototype.scrollTo = function (scrollTarget, scrollDuration, callback) {
|
||||
var _ = this
|
||||
|
||||
var start = new Date().getTime()
|
||||
|
||||
var animateIndex = _.animate_id
|
||||
|
||||
var animate = function () {
|
||||
var now = new Date().getTime() - start
|
||||
_.scrollLeft =
|
||||
_.scrollLeft +
|
||||
(scrollTarget - _.scrollLeft) *
|
||||
_.opt.easing(0, now, 0, 1, scrollDuration)
|
||||
_.ele.scrollLeft = _.scrollLeft
|
||||
|
||||
if (now < scrollDuration && animateIndex === _.animate_id) {
|
||||
_window.requestAnimationFrame(animate)
|
||||
} else {
|
||||
_.ele.scrollLeft = _.scrollLeft = scrollTarget
|
||||
callback && callback.call(_)
|
||||
}
|
||||
}
|
||||
|
||||
_window.requestAnimationFrame(animate)
|
||||
}
|
||||
|
||||
gliderPrototype.removeItem = function (index) {
|
||||
var _ = this
|
||||
|
||||
if (_.slides.length) {
|
||||
_.track.removeChild(_.slides[index])
|
||||
_.refresh(true)
|
||||
_.emit('remove')
|
||||
}
|
||||
}
|
||||
|
||||
gliderPrototype.addItem = function (ele) {
|
||||
var _ = this
|
||||
|
||||
_.track.appendChild(ele)
|
||||
_.refresh(true)
|
||||
_.emit('add')
|
||||
}
|
||||
|
||||
gliderPrototype.handleMouse = function (e) {
|
||||
var _ = this
|
||||
if (_.mouseDown) {
|
||||
_.isDrag = true
|
||||
_.scrollLeft += (_.mouseDown - e.clientX) * (_.opt.dragVelocity || 3.3)
|
||||
_.mouseDown = e.clientX
|
||||
_.ele.scrollLeft = _.scrollLeft
|
||||
}
|
||||
}
|
||||
|
||||
// used to round to the nearest 0.XX fraction
|
||||
gliderPrototype.round = function (double) {
|
||||
var _ = this
|
||||
var step = _.opt.slidesToScroll % 1 || 1
|
||||
var inv = 1.0 / step
|
||||
return Math.round(double * inv) / inv
|
||||
}
|
||||
|
||||
gliderPrototype.refresh = function (paging) {
|
||||
var _ = this
|
||||
_.init(true, paging)
|
||||
}
|
||||
|
||||
gliderPrototype.setOption = function (opt, global) {
|
||||
var _ = this
|
||||
|
||||
if (_.breakpoint && !global) {
|
||||
_._opt.responsive.forEach(function (v) {
|
||||
if (v.breakpoint === _.breakpoint) {
|
||||
v.settings = Object.assign({}, v.settings, opt)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
_._opt = Object.assign({}, _._opt, opt)
|
||||
}
|
||||
|
||||
_.breakpoint = 0
|
||||
_.settingsBreakpoint()
|
||||
}
|
||||
|
||||
gliderPrototype.destroy = function () {
|
||||
var _ = this
|
||||
|
||||
var replace = _.ele.cloneNode(true)
|
||||
|
||||
var clear = function (ele) {
|
||||
ele.removeAttribute('style');
|
||||
[].forEach.call(ele.classList, function (className) {
|
||||
/^glider/.test(className) && ele.classList.remove(className)
|
||||
})
|
||||
}
|
||||
// remove track
|
||||
replace.children[0].outerHTML = replace.children[0].innerHTML
|
||||
clear(replace);
|
||||
[].forEach.call(replace.getElementsByTagName('*'), clear)
|
||||
_.ele.parentNode.replaceChild(replace, _.ele)
|
||||
_.event(_window, 'remove', {
|
||||
resize: _.resize
|
||||
})
|
||||
_.emit('destroy')
|
||||
}
|
||||
|
||||
gliderPrototype.emit = function (name, arg) {
|
||||
var _ = this
|
||||
|
||||
var e = new _window.CustomEvent('glider-' + name, {
|
||||
bubbles: !_.opt.eventPropagate,
|
||||
detail: arg
|
||||
})
|
||||
_.ele.dispatchEvent(e)
|
||||
}
|
||||
|
||||
gliderPrototype.event = function (ele, type, args) {
|
||||
var eventHandler = ele[type + 'EventListener'].bind(ele)
|
||||
Object.keys(args).forEach(function (k) {
|
||||
eventHandler(k, args[k])
|
||||
})
|
||||
}
|
||||
|
||||
return Glider
|
||||
})
|
1
resources/GliderJs/1.7.6/glider.min.css
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.glider,.glider-contain{margin:0 auto;position:relative}.glider,.glider-track{transform:translateZ(0)}.glider-dot,.glider-next,.glider-prev{border:0;padding:0;user-select:none;outline:0}.glider-contain{width:100%}.glider{overflow-y:hidden;-webkit-overflow-scrolling:touch;-ms-overflow-style:none}.glider-track{width:100%;margin:0;padding:0;display:flex;z-index:1}.glider.draggable{user-select:none;cursor:-webkit-grab;cursor:grab}.glider.draggable .glider-slide img{user-select:none;pointer-events:none}.glider.drag{cursor:-webkit-grabbing;cursor:grabbing}.glider-slide{user-select:none;justify-content:center;align-content:center;width:100%;min-width:150px}.glider-slide img{max-width:100%}.glider::-webkit-scrollbar{opacity:0;height:0}.glider-next,.glider-prev{position:absolute;background:0 0;z-index:2;font-size:40px;text-decoration:none;left:-23px;top:30%;cursor:pointer;color:#666;opacity:1;line-height:1;transition:opacity .5s cubic-bezier(.17,.67,.83,.67),color .5s cubic-bezier(.17,.67,.83,.67)}.glider-next:focus,.glider-next:hover,.glider-prev:focus,.glider-prev:hover{color:#ccc}.glider-next{right:-23px;left:auto}.glider-next.disabled,.glider-prev.disabled{opacity:.25;color:#666;cursor:default}.glider-hide{opacity:0}.glider-dots{user-select:none;display:flex;flex-wrap:wrap;justify-content:center;margin:0 auto;padding:0}.glider-dot{display:block;cursor:pointer;color:#ccc;border-radius:999px;background:#ccc;width:12px;height:12px;margin:7px}.glider-dot:focus,.glider-dot:hover{background:#ddd}.glider-dot.active{background:#a89cc8}@media(max-width:36em){.glider::-webkit-scrollbar{opacity:1;-webkit-appearance:none;width:7px;height:3px}.glider::-webkit-scrollbar-thumb{opacity:1;border-radius:99px;background-color:rgba(156,156,156,.25);-webkit-box-shadow:0 0 1px rgba(255,255,255,.25);box-shadow:0 0 1px rgba(255,255,255,.25)}}
|