View source
<?php
define('VIEWS_ISOTOPE_CDN_PATH', 'https://cdnjs.cloudflare.com/ajax/libs/jquery.isotope/2.2.2/isotope.pkgd.min.js');
define('VIEWS_ISOTOPE_FILENAME', 'isotope.pkgd.min.js');
function views_isotope_permission() {
return [
'administer isotope' => [
'title' => t('Administer Isotope Configuration'),
'description' => t('Set configuration options for Isotope'),
],
];
}
function views_isotope_ctools_plugin_api($owner, $api) {
if ($owner == 'views_isotope' && $api == 'default_isotope_configurations') {
return [
'version' => 1,
];
}
}
function views_isotope_default_isotope_configuration() {
$export = [];
$config = new stdClass();
$config->api_version = 1;
$config->name = 'isotope_default_config';
$config->admin_title = 'Default config';
$config->layoutMode = 'masonry';
$config->transitionDuration = NULL;
$config->urlFilters = NULL;
$config->isFitWidth = NULL;
$config->isHorizontal = NULL;
$config->stamp = '.stamp';
$config->horizontalAlignment = NULL;
$config->verticalAlignment = NULL;
$config->isOriginLeft = 1;
if (views_isotope_check_additional_libraries('imagesLoaded')) {
$config->plugins = [
'imagesLoaded',
];
}
else {
$config->plugins = [];
}
$export['isotope_default_config'] = $config;
return $export;
}
function views_isotope_ctools_plugin_directory($module, $type) {
if ($type == 'export_ui') {
return 'plugins/export_ui';
}
}
function views_isotope_context_plugins() {
$plugins = [];
$plugins['IsotopeReaction'] = [
'handler' => [
'path' => drupal_get_path('module', 'views_isotope') . '/plugins/context',
'file' => 'views_isotope_reaction.inc',
'class' => 'IsotopeReaction',
'parent' => 'context_reaction',
],
];
return $plugins;
}
function views_isotope_context_registry() {
return [
'reactions' => [
'isotope' => [
'title' => t('Isotope'),
'description' => t('Set an Isotope configuration.'),
'plugin' => 'IsotopeReaction',
],
],
];
}
function views_isotope_available_configs() {
$available_configs = ctools_export_crud_load_all('isotope_configurations');
foreach ($available_configs as $key => $value) {
$available_configs[$key] = $value->admin_title;
}
return $available_configs;
}
function views_isotope_get_config_json($config, array $additional_attributes) {
ctools_include('export');
$plugin = ctools_export_crud_load('isotope_configurations', $config);
$allowed_attributes = [
'layoutMode',
'transitionDuration',
'urlFilters',
'isFitWidth',
'isHorizontal',
'stamp',
'horizontalAlignment',
'verticalAlignment',
'isOriginLeft',
];
$attributes = [
'columnWidth' => '.isotope-grid-sizer',
'itemSelector' => '.isotope-element',
'gutter' => '.isotope-gutter-sizer',
] + $additional_attributes;
foreach ($plugin as $key => $value) {
if (in_array($key, $allowed_attributes)) {
$attributes[$key] = $value;
}
}
return drupal_json_encode($attributes);
}
function views_isotope_check_library() {
if (function_exists('libraries_get_path') && file_exists(libraries_get_path('isotope') . '/' . VIEWS_ISOTOPE_FILENAME) === TRUE) {
return 'library';
}
if (views_isotope_check_url(VIEWS_ISOTOPE_CDN_PATH)) {
return 'cdn';
}
return FALSE;
}
function views_isotope_additional_libraries_list() {
$libraries['cellsByRow'] = [
'filename' => 'cells-by-row.js',
'type' => 'layout',
'url' => 'https://raw.githubusercontent.com/metafizzy/isotope-cells-by-row/master/cells-by-row.js',
'description' => t('A grid layout where items are centered inside each cell.'),
];
$libraries['packery'] = [
'filename' => 'packery-mode.pkgd.min.js',
'type' => 'layout',
'url' => 'https://raw.githubusercontent.com/metafizzy/isotope-packery/master/packery-mode.pkgd.min.js',
'description' => t('The packery layout mode uses a bin-packing algorithm. This is a fancy way of saying “it fills empty gaps.”'),
];
$libraries['masonryHorizontal'] = [
'filename' => 'masonry-horizontal.js',
'type' => 'layout',
'url' => 'https://raw.githubusercontent.com/metafizzy/isotope-masonry-horizontal/master/masonry-horizontal.js',
'description' => t('masonryHorizontal is the horizontal version of masonry. It works by placing elements in optimal position based on available horizontal space.'),
];
$libraries['fitColumns'] = [
'filename' => 'fit-columns.js',
'type' => 'layout',
'url' => 'https://raw.githubusercontent.com/metafizzy/isotope-fit-columns/master/fit-columns.js',
'description' => t('Items are arranged into columns. Columns progress horizontally. fitColumns is ideal for items that have the same width.'),
];
$libraries['cellsByColumn'] = [
'filename' => 'cells-by-column.js',
'type' => 'layout',
'url' => 'https://raw.githubusercontent.com/metafizzy/isotope-cells-by-column/master/cells-by-column.js',
'description' => t('A horizontal grid layout where items are centered inside each cell.'),
];
$libraries['horizontal'] = [
'filename' => 'horizontal.js',
'type' => 'layout',
'url' => 'https://raw.githubusercontent.com/metafizzy/isotope-horizontal/master/horizontal.js',
'description' => t('Items are arranged horizontally.'),
];
$libraries['imagesLoaded'] = [
'filename' => 'imagesloaded.pkgd.min.js',
'type' => 'plugin',
'url' => 'http://imagesloaded.desandro.com/imagesloaded.pkgd.min.js',
'description' => t('Detect when images have been loaded. (Requires jQuery version 1.9 or later.)'),
];
return $libraries;
}
function views_isotope_check_additional_libraries($libname = FALSE) {
$detected_libraries = [];
$libraries = views_isotope_additional_libraries_list();
if (function_exists('libraries_get_path')) {
foreach ($libraries as $lib_name => $library) {
$layout_path = libraries_get_path('isotope') . '/' . $library['filename'];
if (file_exists($layout_path) === TRUE) {
$detected_libraries[$layout_path] = $lib_name;
}
$plugin_path = libraries_get_path($lib_name) . '/' . $library['filename'];
if (file_exists($plugin_path) === TRUE) {
$detected_libraries[$plugin_path] = $lib_name;
}
}
}
if ($libname && in_array($libname, $detected_libraries)) {
return array_search($libname, $detected_libraries);
}
elseif ($libname) {
return FALSE;
}
return $detected_libraries;
}
function views_isotope_addjs($config_name) {
$isotope_scope = views_isotope_check_library();
if ($isotope_scope == 'library') {
drupal_add_js(libraries_get_path('isotope') . '/' . VIEWS_ISOTOPE_FILENAME);
}
elseif ($isotope_scope == 'cdn') {
drupal_add_js(VIEWS_ISOTOPE_CDN_PATH, 'external');
}
ctools_include('export');
$config = ctools_export_crud_load('isotope_configurations', $config_name);
$libraries = views_isotope_additional_libraries_list();
$selected_libraries = [
$config->layoutMode,
];
foreach ($config->plugins as $value) {
if (!empty($value)) {
$selected_libraries[] = $value;
}
}
foreach ($selected_libraries as $lib_name) {
if (!empty($libraries[$lib_name])) {
$path = views_isotope_check_additional_libraries($lib_name);
if (!empty($path)) {
drupal_add_js($path);
}
}
}
}
function views_isotope_check_url($url) {
$header_response = get_headers($url, 1);
if (strpos($header_response[0], "200") === FALSE) {
return FALSE;
}
return TRUE;
}
function views_isotope_sanitize($raw) {
$safe = $raw;
if (is_array($raw)) {
$safe = [];
foreach ($raw as $i) {
$safe[] = views_isotope_sanitize($i);
}
return implode(' ', $safe);
}
if (function_exists('transliteration_get')) {
$safe = transliteration_get($safe, '?', language_default('language'));
}
$safe = strtolower($safe);
$safe = preg_replace('/[^a-z0-9]/s', '-', $safe);
$safe = preg_replace('/-{2,}/', '-', $safe);
drupal_alter('views_isotope_sanitize', $safe, $raw);
return $safe;
}
function views_isotope_theme($existing, $type, $theme, $path) {
return [
'isotope_grid' => [
'variables' => [
'config' => 'isotope_default_config',
'items' => [],
'instance' => NULL,
],
],
'isotope_filter' => [
'variables' => [
'items' => [],
'instance' => NULL,
'filtername' => 'filter',
'filtertitle' => NULL,
],
],
'isotope_sorter' => [
'variables' => [
'sorts' => [],
'original' => NULL,
'instance' => NULL,
],
],
];
}
function theme_isotope_grid(array $vars) {
$config_name = $vars['config'];
if (module_exists('context')) {
if ($plugin = context_get_plugin('reaction', 'isotope')) {
$context_name = $plugin
->execute();
if (!empty($context_name)) {
$config_name = $context_name;
}
}
}
$additional_config = [
'getSortData' => [],
];
foreach ($vars['items'] as $item) {
$item['data'] = !empty($item['data']) ? $item['data'] : [];
foreach ($item['data'] as $key => $value) {
$additional_config['getSortData'][$key] = '.' . $key;
}
}
$config = views_isotope_get_config_json($config_name, $additional_config);
$global_instances =& drupal_static(__FUNCTION__);
$global_instances = isset($global_instances) ? $global_instances : [];
if (!empty($vars['instance']) && !in_array($vars['instance'], $global_instances)) {
$instance_name = $vars['instance'];
}
else {
for ($i = 0; $i >= 0; $i++) {
if (!in_array($i, $global_instances)) {
$instance_name = $i;
break;
}
}
}
$global_instances[] = $instance_name;
$instance = 'isotope-instance-' . $instance_name;
$items = [
[
'data' => '',
'class' => [
'isotope-grid-sizer',
],
],
[
'data' => '',
'class' => [
'isotope-gutter-sizer',
],
],
];
foreach ($vars['items'] as $item) {
$sorts = '';
$item['data'] = !empty($item['data']) ? $item['data'] : [];
foreach ($item['data'] as $key => $value) {
if (!is_array($value)) {
$value = [
$value,
];
}
foreach ($value as $sort) {
$sorts .= '<div class="sort-data ' . $key . '">' . views_isotope_sanitize($sort) . '</div>';
}
$item['data'][$key] = views_isotope_sanitize($value);
}
$classes = array_values($item['data']);
$classes[] = 'isotope-element';
$items[] = [
'data' => $item['value'] . $sorts,
'class' => $classes,
];
}
$return = [
'#theme' => 'item_list',
'#items' => $items,
'#type' => 'ul',
'#attributes' => [
'class' => 'isotope-container js-isotope',
'id' => $instance,
'data-isotope-options' => $config,
],
'#attached' => [
'js' => [
drupal_get_path('module', 'views_isotope') . '/views_isotope.js',
],
'css' => [
drupal_get_path('module', 'views_isotope') . '/views_isotope.css',
],
],
];
views_isotope_addjs($config_name);
return drupal_render($return);
}
function theme_isotope_filter(array $vars) {
$multi_field_logic = 'OR';
$attributes['class'] = 'isotope-options clearfix';
if (!empty($vars['instance'])) {
$attributes['data-instance-id'] = 'isotope-instance-' . $vars['instance'];
}
if (!empty($vars['filtername'])) {
$attributes['data-filter-group'] = $vars['filtername'];
}
else {
$attributes['data-filter-group'] = 'unnamed_filter';
}
$title = !empty($vars['filtertitle']) ? $vars['filtertitle'] : NULL;
$items[] = l(t('All'), '', [
'attributes' => [
'class' => 'filterbutton',
'data-filter' => '',
],
'fragment' => 'filter',
'external' => TRUE,
]);
foreach ($vars['items'] as $key => $label) {
$keys = explode(',', $key);
foreach ($keys as $k => $v) {
$keys[$k] = '.' . views_isotope_sanitize($v);
}
if ($multi_field_logic == 'OR') {
$keys = implode(', ', $keys);
}
else {
$keys = implode('', $keys);
}
$items[] = l($label, '', [
'attributes' => [
'class' => 'filterbutton',
'data-filter' => $keys,
],
'fragment' => 'filter',
'external' => TRUE,
'html' => TRUE,
]);
}
$return = [
'#theme' => 'item_list',
'#items' => $items,
'#type' => 'ul',
'#title' => $title,
'#attributes' => $attributes,
];
return drupal_render($return);
}
function theme_isotope_sorter(array $vars) {
$attributes['class'] = 'isotope-options sorts clearfix';
if (!empty($vars['instance'])) {
$attributes['data-instance-id'] = 'isotope-instance-' . $vars['instance'];
}
if (!empty($vars['original'])) {
$vars['sorts'] = [
$vars['original'] => 'original-order',
] + $vars['sorts'];
}
foreach ($vars['sorts'] as $key => $value) {
$sort = is_array($value) ? implode(',', $value) : $value;
$label = empty($key) || is_numeric($key) ? $sort : $key;
$items[] = l($label, '', [
'attributes' => [
'class' => 'sorterbutton',
'data-sort-by' => $sort,
],
'fragment' => 'sorter',
'external' => TRUE,
'html' => TRUE,
]);
}
$return = [
'#theme' => 'item_list',
'#items' => $items,
'#type' => 'ul',
'#title' => t('Sort By'),
'#attributes' => $attributes,
];
return drupal_render($return);
}