skinr_ui.admin.inc 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110
  1. <?php
  2. /**
  3. * @file
  4. * Admin page callbacks for the Skinr module.
  5. */
  6. /**
  7. * Menu callback; Updates the skin configuration's status.
  8. */
  9. function skinr_ui_skin_status_set($skin, $status) {
  10. // We require a token in the query string to prevent CSFR attacks.
  11. if (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], 'admin/structure/skinr/skin/' . $skin->sid . '/' . ($status ? 'enable' : 'disable'))) {
  12. return MENU_ACCESS_DENIED;
  13. }
  14. // Load an uncached version of the skin configuration object.
  15. $skin = skinr_skin_load_unchanged($skin->sid);
  16. // Let's save some time in skinr_skin_save() by setting $skin->original here.
  17. $skin->original = clone($skin);
  18. // Update the status and save the skin configuration.
  19. $skin->status = $status ? 1 : 0;
  20. skinr_skin_save($skin);
  21. if ($status) {
  22. drupal_set_message(t('Skin configuration has been enabled.'));
  23. }
  24. else {
  25. drupal_set_message(t('Skin configuration has been disabled.'));
  26. }
  27. // Return to the skin configuration overview page.
  28. drupal_goto('admin/structure/skinr');
  29. }
  30. /**
  31. * Implements hook_skinr_ui_operations().
  32. */
  33. function skinr_ui_skinr_ui_operations() {
  34. $operations = array(
  35. 'enable' => array(
  36. 'label' => t('Enable selected skin configuration'),
  37. 'callback' => 'skinr_ui_mass_update',
  38. 'callback arguments' => array('updates' => array('status' => 1)),
  39. ),
  40. 'disable' => array(
  41. 'label' => t('Disable selected skin configuration'),
  42. 'callback' => 'skinr_ui_mass_update',
  43. 'callback arguments' => array('updates' => array('status' => 0)),
  44. ),
  45. 'delete' => array(
  46. 'label' => t('Delete selected skin configuration'),
  47. 'callback' => NULL,
  48. ),
  49. );
  50. return $operations;
  51. }
  52. /**
  53. * List skinr administration filters that can be applied.
  54. *
  55. * @return
  56. * An array of filters.
  57. */
  58. function skinr_ui_filters() {
  59. // Theme filter.
  60. $themes = list_themes();
  61. ksort($themes);
  62. $options = array('[any]' => t('any'));
  63. foreach ($themes as $theme) {
  64. if (!$theme->status) {
  65. continue;
  66. }
  67. $options[$theme->name] = $theme->info['name'];
  68. }
  69. $filters['theme'] = array(
  70. 'title' => t('theme'),
  71. 'options' => $options,
  72. );
  73. // Type filter.
  74. $config = skinr_get_config_info();
  75. $options = array('[any]' => t('any'));
  76. foreach ($config as $type) {
  77. $options[$type] = $type;
  78. }
  79. $filters['module'] = array(
  80. 'title' => t('type'),
  81. 'options' => $options,
  82. );
  83. // Skin filter.
  84. $skin_info = skinr_get_skin_info();
  85. $options = array('[any]' => t('any'), '_additional' => t('Additional classes'));
  86. foreach ($skin_info as $skin => $info) {
  87. $options[$skin] = $info['title'];
  88. }
  89. $filters['skin'] = array(
  90. 'title' => t('skin'),
  91. 'options' => $options,
  92. );
  93. // Status filter.
  94. $filters['status'] = array(
  95. 'title' => t('status'),
  96. 'options' => array(
  97. '[any]' => t('any'),
  98. '1' => t('enabled'),
  99. '0' => t('disabled'),
  100. ),
  101. );
  102. return $filters;
  103. }
  104. /**
  105. * Apply filters for skin configuration administration filters based on session.
  106. *
  107. * @param $query
  108. * A SelectQuery to which the filters should be applied.
  109. */
  110. function skinr_ui_build_filter_query(SelectQueryInterface $query) {
  111. // Build query
  112. $filter_data = isset($_SESSION['skinr_ui_overview_filter']) ? $_SESSION['skinr_ui_overview_filter'] : array();
  113. foreach ($filter_data as $index => $filter) {
  114. list($key, $value) = $filter;
  115. $query->condition('s.' . $key, $value);
  116. }
  117. }
  118. /**
  119. * Form builder for the Skinr administration filters form.
  120. *
  121. * @ingroup forms
  122. */
  123. function skinr_ui_filter_form() {
  124. $session = &$_SESSION['skinr_ui_overview_filter'];
  125. $session = is_array($session) ? $session : array();
  126. $filters = skinr_ui_filters();
  127. $i = 0;
  128. $form['filters'] = array(
  129. '#type' => 'fieldset',
  130. '#title' => t('Show only items where'),
  131. '#theme' => 'exposed_filters__skinr',
  132. );
  133. foreach ($session as $filter) {
  134. list($type, $value) = $filter;
  135. $value = $filters[$type]['options'][$value];
  136. $t_args = array('%property' => $filters[$type]['title'], '%value' => $value);
  137. if ($i++) {
  138. $form['filters']['current'][] = array('#markup' => t('and where %property is %value', $t_args));
  139. }
  140. else {
  141. $form['filters']['current'][] = array('#markup' => t('where %property is %value', $t_args));
  142. }
  143. // Remove the option if it is already being filtered on.
  144. unset($filters[$type]);
  145. }
  146. $form['filters']['status'] = array(
  147. '#type' => 'container',
  148. '#attributes' => array('class' => array('clearfix')),
  149. '#prefix' => ($i ? '<div class="additional-filters">' . t('and where') . '</div>' : ''),
  150. );
  151. $form['filters']['status']['filters'] = array(
  152. '#type' => 'container',
  153. '#attributes' => array('class' => array('filters')),
  154. );
  155. foreach ($filters as $key => $filter) {
  156. $names[$key] = $filter['title'];
  157. $form['filters']['status']['filters'][$key] = array(
  158. '#type' => 'select',
  159. '#title' => $filter['title'],
  160. '#options' => $filter['options'],
  161. '#default_value' => '[any]',
  162. );
  163. }
  164. $form['filters']['status']['actions'] = array(
  165. '#type' => 'actions',
  166. '#id' => 'skinr-exposed-filters',
  167. '#attributes' => array('class' => array('container-inline')),
  168. );
  169. if (count($filters)) {
  170. $form['filters']['status']['actions']['submit'] = array(
  171. '#type' => 'submit',
  172. '#value' => count($session) ? t('Refine') : t('Filter'),
  173. );
  174. }
  175. if (count($session)) {
  176. $form['filters']['status']['actions']['undo'] = array('#type' => 'submit', '#value' => t('Undo'));
  177. $form['filters']['status']['actions']['reset'] = array('#type' => 'submit', '#value' => t('Reset'));
  178. }
  179. drupal_add_js('misc/form.js');
  180. return $form;
  181. }
  182. /**
  183. * Mass update skin configurations, updating all skin configurations in the
  184. * $skins array with the field values in $updates.
  185. *
  186. * IMPORTANT NOTE: This function is intended to work when called
  187. * from a form submit handler. Calling it outside of the form submission
  188. * process may not work correctly.
  189. *
  190. * @param array $skins
  191. * Array of skin configuration sids to update.
  192. * @param array $updates
  193. * Array of key/value pairs with skin configuration field names and the
  194. * value to update that field to.
  195. */
  196. function skinr_ui_mass_update($skins, $updates) {
  197. // We use batch processing to prevent timeout when updating a large number
  198. // of skins.
  199. if (count($skins) > 10) {
  200. $batch = array(
  201. 'operations' => array(
  202. array('_skinr_ui_mass_update_batch_process', array($skins, $updates))
  203. ),
  204. 'finished' => '_skinr_ui_mass_update_batch_finished',
  205. 'title' => t('Processing'),
  206. // We use a single multi-pass operation, so the default
  207. // 'Remaining x of y operations' message will be confusing here.
  208. 'progress_message' => '',
  209. 'error_message' => t('The update has encountered an error.'),
  210. // The operations do not live in the .module file, so we need to
  211. // tell the batch engine which file to load before calling them.
  212. 'file' => drupal_get_path('module', 'skinr_ui') . '/skinr_ui.admin.inc',
  213. );
  214. batch_set($batch);
  215. }
  216. else {
  217. foreach ($skins as $sid) {
  218. _skinr_ui_mass_update_helper($sid, $updates);
  219. }
  220. drupal_set_message(t('The update has been performed.'));
  221. }
  222. }
  223. /**
  224. * Helper function for skin configuration mass updates.
  225. */
  226. function _skinr_ui_mass_update_helper($sid, $updates) {
  227. drupal_static_reset('skinr_skin_load_multiple');
  228. $skin = skinr_skin_load($sid);
  229. // For efficiency manually store the original skin configuration before
  230. // applying any changes.
  231. $skin->original = clone $skin;
  232. foreach ($updates as $name => $value) {
  233. $skin->$name = $value;
  234. }
  235. skinr_skin_save($skin);
  236. return $skin;
  237. }
  238. /**
  239. * Batch operation for skin configuration mass updates.
  240. */
  241. function _skinr_ui_mass_update_batch_process($skins, $updates, &$context) {
  242. if (!isset($context['sandbox']['progress'])) {
  243. $context['sandbox']['progress'] = 0;
  244. $context['sandbox']['max'] = count($skins);
  245. $context['sandbox']['skins'] = $skins;
  246. }
  247. // Process skins in groups of 5.
  248. $count = min(5, count($context['sandbox']['skins']));
  249. for ($i = 1; $i <= $count; $i++) {
  250. // For each sid, load the skin configuration, reset the values, and save it.
  251. $sid = array_shift($context['sandbox']['skins']);
  252. $skin = _skinr_ui_mass_update_helper($sid, $updates);
  253. // Store result for post-processing in the finished callback.
  254. // @todo
  255. $context['results'][] = l($skin->title, 'node/' . $skin->sid);
  256. // Update our progress information.
  257. $context['sandbox']['progress']++;
  258. }
  259. // Inform the batch engine that we are not finished,
  260. // and provide an estimation of the completion level we reached.
  261. if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
  262. $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
  263. }
  264. }
  265. /**
  266. * Batch 'finished' callback for skin configuration mass updates.
  267. */
  268. function _skinr_ui_mass_update_batch_finished($success, $results, $operations) {
  269. if ($success) {
  270. drupal_set_message(t('The update has been performed.'));
  271. }
  272. else {
  273. drupal_set_message(t('An error occurred and processing did not complete.'), 'error');
  274. $message = format_plural(count($results), '1 item successfully processed:', '@count items successfully processed:');
  275. $message .= theme('item_list', array('items' => $results));
  276. drupal_set_message($message);
  277. }
  278. }
  279. /**
  280. * Form submission handler for skinr_ui_filter_form().
  281. */
  282. function skinr_ui_filter_form_submit($form, &$form_state) {
  283. $filters = skinr_ui_filters();
  284. switch ($form_state['values']['op']) {
  285. case t('Filter'):
  286. case t('Refine'):
  287. // Apply every filter that has a choice selected other than 'any'.
  288. foreach ($filters as $filter => $options) {
  289. if (isset($form_state['values'][$filter]) && $form_state['values'][$filter] != '[any]') {
  290. // Flatten the options array to accommodate hierarchical/nested options.
  291. $flat_options = form_options_flatten($filters[$filter]['options']);
  292. // Only accept valid selections offered on the dropdown, block bad input.
  293. if (isset($flat_options[$form_state['values'][$filter]])) {
  294. $_SESSION['skinr_ui_overview_filter'][] = array($filter, $form_state['values'][$filter]);
  295. }
  296. }
  297. }
  298. break;
  299. case t('Undo'):
  300. array_pop($_SESSION['skinr_ui_overview_filter']);
  301. break;
  302. case t('Reset'):
  303. $_SESSION['skinr_ui_overview_filter'] = array();
  304. break;
  305. }
  306. }
  307. /**
  308. * Menu callback: skin configurations administration.
  309. *
  310. * @ingroup forms
  311. */
  312. function skinr_ui_list($form, &$form_state) {
  313. if (isset($form_state['values']['operation']) && $form_state['values']['operation'] == 'delete') {
  314. return skinr_ui_multiple_delete_confirm($form, $form_state, array_filter($form_state['values']['skins']));
  315. }
  316. $form['filter'] = skinr_ui_filter_form();
  317. $form['#submit'][] = 'skinr_ui_filter_form_submit';
  318. $form['admin'] = skinr_ui_admin_skins();
  319. return $form;
  320. }
  321. /**
  322. * Form builder: Builds the skin configuration administration overview.
  323. *
  324. * @ingroup forms
  325. */
  326. function skinr_ui_admin_skins() {
  327. // Build the 'Update options' form.
  328. $form['options'] = array(
  329. '#type' => 'fieldset',
  330. '#title' => t('Update options'),
  331. '#attributes' => array('class' => array('container-inline')),
  332. );
  333. $options = array();
  334. foreach (module_invoke_all('skinr_ui_operations') as $operation => $array) {
  335. $options[$operation] = $array['label'];
  336. }
  337. $form['options']['operation'] = array(
  338. '#type' => 'select',
  339. '#title' => t('Operation'),
  340. '#title_display' => 'invisible',
  341. '#options' => $options,
  342. '#default_value' => 'enable',
  343. );
  344. $form['options']['submit'] = array(
  345. '#type' => 'submit',
  346. '#value' => t('Update'),
  347. '#validate' => array('skinr_ui_admin_skins_validate'),
  348. '#submit' => array('skinr_ui_admin_skins_submit'),
  349. );
  350. $header = array(
  351. 'theme' => array('data' => t('Theme'), 'field' => 's.theme'),
  352. 'type' => array('data' => t('Type'), 'field' => 's.module'),
  353. 'element' => array('data' => t('Element ID'), 'field' => 's.element'),
  354. 'skin' => array('data' => t('Skin'), 'field' => 's.skin'),
  355. 'status' => array('data' => t('Status'), 'field' => 's.status'),
  356. 'operations' => array('data' => t('Operations')),
  357. );
  358. $query = db_select('skinr_skins', 's')->extend('PagerDefault')->extend('TableSort');
  359. skinr_ui_build_filter_query($query);
  360. $sids = $query
  361. ->fields('s', array('sid'))
  362. ->limit(50)
  363. ->orderByHeader($header)
  364. ->execute()
  365. ->fetchCol();
  366. $skins = skinr_skin_load_multiple($sids);
  367. $themes = list_themes();
  368. $skin_info = skinr_get_skin_info();
  369. $destination = drupal_get_destination();
  370. $options = array();
  371. foreach ($skins as $skin) {
  372. $operations = array(
  373. 'edit' => array(
  374. 'title' => t('edit'),
  375. 'href' => 'admin/structure/skinr/edit/nojs/' . $skin->module . '/' . $skin->element,
  376. 'query' => $destination,
  377. ),
  378. 'status' => array(
  379. 'title' => $skin->status ? t('disable') : t('enable'),
  380. 'href' => 'admin/structure/skinr/skin/' . $skin->sid . '/' . ($skin->status ? 'disable' : 'enable'),
  381. 'query' => $destination + array(
  382. 'token' => drupal_get_token('admin/structure/skinr/skin/' . $skin->sid . '/' . ($skin->status ? 'disable' : 'enable')),
  383. ),
  384. ),
  385. 'delete' => array(
  386. 'title' => t('delete'),
  387. 'href' => 'admin/structure/skinr/skin/' . $skin->sid . '/delete',
  388. 'query' => $destination,
  389. ),
  390. );
  391. $options[$skin->sid] = array(
  392. 'theme' => isset($themes[$skin->theme]) ? $themes[$skin->theme]->info['name'] : '<em>' . $skin->theme . '</em>',
  393. 'type' => $skin->module,
  394. 'element' => $skin->element,
  395. 'skin' => $skin->skin == '_additional' ? '<em>' . t('Additional classes') . '</em>' : (isset($skin_info[$skin->skin]) ? $skin_info[$skin->skin]['title'] : '<em>' . $skin->skin . '</em>'),
  396. 'status' => $skin->status ? t('enabled') : t('disabled'),
  397. 'operations' => array(
  398. 'data' => array(
  399. '#theme' => 'links__skinr_ui_operations',
  400. '#links' => $operations,
  401. '#attributes' => array('class' => array('links', 'inline')),
  402. ),
  403. ),
  404. );
  405. }
  406. $form['skins'] = array(
  407. '#type' => 'tableselect',
  408. '#header' => $header,
  409. '#options' => $options,
  410. '#empty' => t('No content available.'),
  411. );
  412. $form['pager'] = array('#markup' => theme('pager'));
  413. return $form;
  414. }
  415. /**
  416. * Form validation handler for skinr_ui_list().
  417. *
  418. * Check if any skinr settings have been selected to perform the chosen
  419. * 'Update option' on.
  420. */
  421. function skinr_ui_admin_skins_validate($form, &$form_state) {
  422. // Error if there are no items to select.
  423. if (!is_array($form_state['values']['skins']) || !count(array_filter($form_state['values']['skins']))) {
  424. form_set_error('', t('No items selected.'));
  425. }
  426. }
  427. /**
  428. * Form submission handler for skinr_ui_list().
  429. *
  430. * Execute the chosen 'Update option' on the selected skinr settings.
  431. */
  432. function skinr_ui_admin_skins_submit($form, &$form_state) {
  433. $operations = module_invoke_all('skinr_ui_operations');
  434. $operation = $operations[$form_state['values']['operation']];
  435. // Filter out unchecked nodes
  436. $nodes = array_filter($form_state['values']['skins']);
  437. if ($function = $operation['callback']) {
  438. // Add in callback arguments if present.
  439. if (isset($operation['callback arguments'])) {
  440. $args = array_merge(array($nodes), $operation['callback arguments']);
  441. }
  442. else {
  443. $args = array($nodes);
  444. }
  445. call_user_func_array($function, $args);
  446. cache_clear_all();
  447. }
  448. else {
  449. // We need to rebuild the form to go to a second step. For example, to
  450. // show the confirmation form for the deletion of nodes.
  451. $form_state['rebuild'] = TRUE;
  452. }
  453. }
  454. /**
  455. * Form builder for the confirmation form when deleting multiple Skinr settings.
  456. *
  457. * @param $skins
  458. * An array of skins to delete.
  459. *
  460. * @ingroup forms
  461. */
  462. function skinr_ui_multiple_delete_confirm($form, &$form_state, $skins) {
  463. $themes = list_themes();
  464. $form['skins'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
  465. // array_filter returns only elements with TRUE values
  466. $original_skins = skinr_skin_load_multiple(array_keys($skins));
  467. foreach ($skins as $sid => $value) {
  468. $form['skins'][$sid] = array(
  469. '#type' => 'hidden',
  470. '#value' => $sid,
  471. '#prefix' => '<li>',
  472. '#suffix' => t('Skin %skin for element %element of type %type for the %theme theme', array('%skin' => $original_skins[$sid]->skin, '%element' => $original_skins[$sid]->element, '%type' => $original_skins[$sid]->module, '%theme' => $themes[$original_skins[$sid]->theme]->info['name'])) ."</li>\n",
  473. );
  474. }
  475. $form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
  476. $form['#submit'][] = 'skinr_ui_multiple_delete_confirm_submit';
  477. $confirm_question = format_plural(count($skins),
  478. 'Are you sure you want to delete this item?',
  479. 'Are you sure you want to delete these items?');
  480. return confirm_form($form,
  481. $confirm_question,
  482. 'admin/structure/skinr', t('This action cannot be undone.'),
  483. t('Delete'), t('Cancel'));
  484. }
  485. /**
  486. * Form submission handler for skinr_ui_multiple_delete_confirm().
  487. */
  488. function skinr_ui_multiple_delete_confirm_submit($form, &$form_state) {
  489. if ($form_state['values']['confirm']) {
  490. skinr_skin_delete_multiple(array_keys($form_state['values']['skins']));
  491. $count = count($form_state['values']['skins']);
  492. if ($count == 1) {
  493. watchdog('content', 'Deleted 1 skin configuration.');
  494. }
  495. else {
  496. watchdog('content', 'Deleted @count skin configurations.', array('@count' => $count));
  497. }
  498. drupal_set_message(format_plural($count, 'Deleted 1 skin configuration.', 'Deleted @count skin configurations.'));
  499. }
  500. $form_state['redirect'] = 'admin/structure/skinr';
  501. }
  502. /**
  503. * Menu callback for admin/structure/block.
  504. *
  505. * @param $theme
  506. * The theme to display the administration page for. If not provided, defaults
  507. * to the currently used theme.
  508. */
  509. function skinr_ui_admin_library($theme = NULL) {
  510. global $theme_key;
  511. drupal_theme_initialize();
  512. if (!isset($theme)) {
  513. // If theme is not specifically set, rehash for the current theme.
  514. $theme = $theme_key;
  515. }
  516. return drupal_get_form('skinr_ui_admin_library_form', $theme);
  517. }
  518. /**
  519. * Menu callback: skins administration.
  520. */
  521. function skinr_ui_admin_library_form($form, $form_state, $theme) {
  522. $form['edited_theme'] = array(
  523. '#type' => 'value',
  524. '#value' => $theme,
  525. );
  526. $skins = skinr_get_skin_info();
  527. if (empty($skins)) {
  528. $form['skins_empty'] = array(
  529. '#markup' => t("You don't have any skins to manage."),
  530. );
  531. return $form;
  532. }
  533. if (isset($form_state['storage']['sids'])) {
  534. // Ask for confirmation for disabling skin configurations.
  535. foreach ($form_state['storage']['skins'] as $skin) {
  536. $items[] = $skins[$skin]['title'];
  537. }
  538. $message = t('Would you like to disable all skin configurations for the selected skins?') . theme('item_list', array('items' => $items));
  539. // Insert a confirmation form.
  540. return confirm_form(
  541. $form,
  542. t('Disable all skin configurations for selected skins?'),
  543. 'admin/structure/skinr/library',
  544. $message,
  545. t('Yes'),
  546. t('No')
  547. );
  548. }
  549. // Apply overridden status.
  550. foreach ($skins as $name => $skin_info) {
  551. $skins[$name]['status'] = skinr_skin_info_status_get($skins[$name]);
  552. }
  553. $groups = skinr_get_group_info();
  554. uasort($skins, 'skinr_ui_sort_by_title');
  555. $form['skins'] = array('#tree' => TRUE);
  556. // Iterate through each of the skins.
  557. foreach ($skins as $name => $skin_info) {
  558. $extra = array();
  559. // Set status.
  560. $extra['enabled'] = $skin_info['status'][$theme];
  561. // Create a row entry for this skin.
  562. $group = $groups[$skin_info['group']]['title'];
  563. $form['skins'][$group][$name] = _skinr_ui_admin_library_form_build_row($skin_info, $extra, $theme);
  564. }
  565. // Add basic information to the fieldsets.
  566. foreach (element_children($form['skins']) as $package) {
  567. $form['skins'][$package] += array(
  568. '#type' => 'fieldset',
  569. '#title' => $package,
  570. '#collapsible' => TRUE,
  571. '#theme' => 'skinr_ui_admin_library_fieldset',
  572. '#header' => array(
  573. array('data' => t('Enabled'), 'class' => array('checkbox')),
  574. t('Name'),
  575. t('Source'),
  576. t('Version'),
  577. t('Theme hooks'),
  578. ),
  579. );
  580. }
  581. $form['actions'] = array('#type' => 'actions');
  582. $form['actions']['submit'] = array(
  583. '#type' => 'submit',
  584. '#value' => t('Save configuration'),
  585. );
  586. $form['actions']['reset'] = array(
  587. '#type' => 'submit',
  588. '#value' => t('Reset to defaults'),
  589. );
  590. $form['#action'] = url('admin/structure/skinr/library');
  591. return $form;
  592. }
  593. /**
  594. * Build a table row for the skin info listing page.
  595. */
  596. function _skinr_ui_admin_library_form_build_row($skin_info, $extra, $theme) {
  597. // Add in the defaults.
  598. $extra += array(
  599. 'enabled' => FALSE,
  600. 'disabled' => FALSE,
  601. 'links' => array(),
  602. );
  603. $form = array(
  604. '#tree' => TRUE,
  605. );
  606. $form['name'] = array(
  607. '#markup' => $skin_info['title'],
  608. );
  609. $form['description'] = array(
  610. '#markup' => t($skin_info['description']),
  611. );
  612. // Grab source info.
  613. $info = system_get_info($skin_info['source']['type'], $skin_info['source']['name']);
  614. $source = !empty($info['name']) ? $info['name'] : $skin_info['source']['name'];
  615. $form['source'] = array(
  616. '#markup' => t('%source !type', array('%source' => $source, '!type' => $skin_info['source']['type'] == 'module' ? t('module') : t('theme'))),
  617. );
  618. $form['version'] = array(
  619. '#markup' => $skin_info['source']['version'],
  620. );
  621. $theme_hooks = array();
  622. foreach ($skin_info['theme hooks'] as $theme_hook) {
  623. $theme_hooks[] = $theme_hook == '*' ? t('all hooks') : $theme_hook;
  624. }
  625. $form['theme hooks'] = array(
  626. '#markup' => implode('<br />', $theme_hooks),
  627. );
  628. $form['enable'] = array(
  629. '#type' => 'checkbox',
  630. '#title' => t('Enable'),
  631. '#default_value' => $extra['enabled'],
  632. );
  633. if ($extra['disabled']) {
  634. $form['enable']['#disabled'] = TRUE;
  635. }
  636. return $form;
  637. }
  638. /**
  639. * Sort skin infos by title.
  640. *
  641. * @param $a
  642. * The first skin info to compare.
  643. * @param $b
  644. * The second skin info to compare.
  645. *
  646. * @return
  647. * Returns < 0 if $a is less than $b; > 0 if $a is greater than $b, and 0
  648. * if they are equal.
  649. */
  650. function skinr_ui_sort_by_title($a, $b) {
  651. return strcasecmp($a['title'], $b['title']);
  652. }
  653. /**
  654. * Form submission handler for skinr_ui_admin_library_form().
  655. */
  656. function skinr_ui_admin_library_form_submit($form, &$form_state) {
  657. $skins = skinr_get_skin_info();
  658. $theme = $form_state['values']['edited_theme'];
  659. $theme_info = system_get_info('theme', $theme);
  660. $reset = $form_state['clicked_button']['#id'] == 'edit-reset' ? TRUE : FALSE;
  661. if ($reset) {
  662. // Reset all values to their default.
  663. foreach ($form_state['values']['skins'] as $category => $data) {
  664. foreach ($data as $skin => $enabled) {
  665. $default_status = isset($skins[$skin]['status'][$theme]) ? $skins[$skin]['status'][$theme] : $skins[$skin]['default status'];
  666. $form_state['values']['skins'][$category][$skin]['enable'] = $default_status;
  667. }
  668. }
  669. }
  670. if ($form_state['clicked_button']['#id'] == 'edit-submit' || $reset) {
  671. // Make sure we don't disable skins for which configuration exists. Ask to
  672. // disable all related skin configurations so we can disable the skin.
  673. $affected_skins = array();
  674. $disable_sids = array();
  675. $rebuild = FALSE;
  676. foreach ($form_state['values']['skins'] as $category => $data) {
  677. foreach ($data as $skin => $enabled) {
  678. $enabled = $enabled['enable'];
  679. $status = skinr_skin_info_status_get($skins[$skin]);
  680. if (!empty($status[$theme]) && !$enabled) {
  681. // This skin is being disabled.
  682. $affected_skins[] = $skin;
  683. // Find all enabled configurations for this skin.
  684. $params = array(
  685. 'theme' => $theme,
  686. 'skin' => $skin,
  687. 'status' => 1,
  688. );
  689. $sids = skinr_skin_get_sids($params);
  690. if (count($sids)) {
  691. $disable_sids += $sids;
  692. $rebuild = TRUE;
  693. }
  694. }
  695. }
  696. }
  697. if ($rebuild) {
  698. $form_state['storage']['status'] = $form_state['values']['skins'];
  699. $form_state['storage']['skins'] = $affected_skins;
  700. $form_state['storage']['sids'] = $disable_sids;
  701. $form_state['storage']['reset'] = $reset;
  702. $form_state['rebuild'] = TRUE;
  703. return;
  704. }
  705. }
  706. if (!empty($form_state['storage']['sids'])) {
  707. // Disable any configurations for skins that are being disabled.
  708. db_update('skinr_skins')
  709. ->fields(array('status' => 0))
  710. ->condition('sid', $form_state['storage']['sids'])
  711. ->execute();
  712. // Clear skinr_skin_load_multiple cache.
  713. drupal_static_reset('skinr_skin_load_multiple');
  714. foreach ($form_state['storage']['skins'] as $skin) {
  715. drupal_set_message(t('Disabled all skin configurations for skin %skin and theme %theme.', array('%skin' => $skin, '%theme' => $theme_info['name'])));
  716. }
  717. $changed_status = $form_state['storage']['status'];
  718. $reset = $form_state['storage']['reset'];
  719. }
  720. else {
  721. $changed_status = $form_state['values']['skins'];
  722. }
  723. // Save new status.
  724. foreach ($changed_status as $category => $data) {
  725. foreach ($data as $skin => $enabled) {
  726. $enabled = $enabled['enable'];
  727. $status = skinr_skin_info_status_get($skins[$skin]);
  728. if (!isset($status[$theme]) || $status[$theme] != $enabled) {
  729. // Update status.
  730. $status[$theme] = $enabled;
  731. skinr_skin_info_status_set($skins[$skin], $status);
  732. }
  733. }
  734. }
  735. if ($reset) {
  736. drupal_set_message(t("Statuses for %theme's skins have been reset to their defaults.", array('%theme' => $theme_info['name'])));
  737. }
  738. else {
  739. drupal_set_message(t("Statuses for %theme's skins have been updated.", array('%theme' => $theme_info['name'])));
  740. }
  741. $form_state['redirect'] = 'admin/structure/skinr/library';
  742. }
  743. /**
  744. * Returns HTML for the skin info listing form.
  745. *
  746. * @param $variables
  747. * An associative array containing:
  748. * - form: A render element representing the form.
  749. *
  750. * @ingroup themeable
  751. */
  752. function theme_skinr_ui_admin_library_fieldset($variables) {
  753. $form = $variables['form'];
  754. // Individual table headers.
  755. $rows = array();
  756. // Iterate through all the modules, which are
  757. // children of this fieldset.
  758. foreach (element_children($form) as $skin_name) {
  759. // Stick it into $skinset for easier accessing.
  760. $skin_info = $form[$skin_name];
  761. $row = array();
  762. // Enabled.
  763. unset($skin_info['enable']['#title']);
  764. $row[] = array('class' => array('checkbox'), 'data' => drupal_render($skin_info['enable']));
  765. // Name.
  766. $row[] = theme('skinr_ui_admin_library_summary', array(
  767. 'name' => drupal_render($skin_info['name']),
  768. 'description' => drupal_render($skin_info['description']),
  769. ));
  770. // Source.
  771. $row[] = drupal_render($skin_info['source']);
  772. $row[] = drupal_render($skin_info['version']);
  773. // Theme hooks.
  774. $row[] = drupal_render($skin_info['theme hooks']);
  775. $rows[] = $row;
  776. }
  777. return theme('table', array('header' => $form['#header'], 'rows' => $rows));
  778. }
  779. /**
  780. * Returns HTML for a message about incompatible skinsets.
  781. *
  782. * @param $variables
  783. * An associative array containing:
  784. * - message: The form array representing the currently disabled modules.
  785. *
  786. * @ingroup themeable
  787. */
  788. function theme_skinr_ui_admin_library_summary($variables) {
  789. return '<div class="skin-infos-summary"><h2>'. $variables['name'] .'</h2><div class="description">'. $variables['description'] .'</div></div>';
  790. }
  791. /**
  792. * Form builder for the Skinr settings export form.
  793. *
  794. * @param $theme
  795. * (optional) The name of the theme to export Skinr settings for. If no
  796. * theme name is provided a theme selector is shown.
  797. *
  798. * @ingroup forms
  799. */
  800. function skinr_ui_export_form($form, &$form_state, $theme = NULL) {
  801. $form = array();
  802. $themes = list_themes();
  803. if ($theme) {
  804. // Export an individual theme.
  805. $theme = str_replace('-', '_', $theme);
  806. $params = array(
  807. 'theme' => $theme,
  808. );
  809. $skins = skinr_skin_load_multiple(skinr_skin_get_sids($params));
  810. // Convert classes to arrays.
  811. $code = '';
  812. foreach ($skins as $skin) {
  813. unset($skin->sid);
  814. unset($skin->rdf_mapping);
  815. $code .= '$skins[] = '. var_export((array) $skin, TRUE) .";\n";
  816. }
  817. $lines = substr_count($code, "\n") + 1;
  818. $form['theme'] = array(
  819. '#type' => 'textfield',
  820. '#title' => t('Theme'),
  821. '#value' => $themes[$theme]->info['name'],
  822. '#disabled' => TRUE,
  823. );
  824. $form['skinr_settings'] = array(
  825. '#type' => 'textarea',
  826. '#title' => t('Skinr settings'),
  827. '#default_value' => $code,
  828. '#rows' => min($lines, 150),
  829. );
  830. }
  831. else {
  832. // Give the option for which theme to export.
  833. $options = array();
  834. ksort($themes);
  835. $current_theme = skinr_current_theme(TRUE);
  836. // Put default theme at the top.
  837. $options[$current_theme] = $themes[$current_theme]->info['name']. ' [' . t('default') . ']';
  838. foreach ($themes as $theme) {
  839. if (!empty($theme->info['hidden'])) {
  840. continue;
  841. }
  842. if ($theme->name == $current_theme) {
  843. // Do nothing.
  844. }
  845. elseif ($theme->status) {
  846. $options[$theme->name] = $theme->info['name'] . ' [' . t('enabled') . ']';
  847. }
  848. else {
  849. $options[$theme->name] = $theme->info['name'];
  850. }
  851. }
  852. $form['theme'] = array(
  853. '#type' => 'select',
  854. '#title' => t('Theme'),
  855. '#description' => t('Theme to export the skinr settings for.'),
  856. '#options' => $options,
  857. '#required' => TRUE,
  858. );
  859. $form['submit'] = array(
  860. '#type' => 'submit',
  861. '#value' => t('Export'),
  862. );
  863. }
  864. return $form;
  865. }
  866. /**
  867. * Form validation handler for skinr_ui_export_form().
  868. */
  869. function skinr_ui_export_form_validate(&$form, &$form_state) {
  870. if (!empty($form_state['values']['theme']) && preg_match('/[^a-zA-Z0-9_]/', $form_state['values']['theme'])) {
  871. form_error($form['theme'], t('The theme name must be alphanumeric and can contain underscores only.'));
  872. }
  873. }
  874. /**
  875. * Form submission handler for skinr_ui_export_form().
  876. */
  877. function skinr_ui_export_form_submit(&$form, &$form_state) {
  878. drupal_goto('admin/structure/skinr/export/' . str_replace('_', '-', $form_state['values']['theme']));
  879. }
  880. /**
  881. * Form builder for the Skinr settings import form.
  882. *
  883. * @ingroup forms
  884. */
  885. function skinr_ui_import_form($form, &$form_state) {
  886. $form['skin_configurations'] = array(
  887. '#type' => 'textarea',
  888. '#title' => t('Skin configurations'),
  889. '#description' => t('Paste skin coonfigurations here.'),
  890. '#rows' => 16,
  891. );
  892. $form['submit'] = array(
  893. '#type' => 'submit',
  894. '#value' => t('Import'),
  895. );
  896. return $form;
  897. }
  898. /**
  899. * Form validation handler for skinr_ui_import_form().
  900. */
  901. function skinr_ui_import_form_validate(&$form, &$form_state) {
  902. if (empty($form_state['values']['skin_configurations'])) {
  903. // Error.
  904. form_error($form['skin_configurations'], t('These are not valid skin configurations.'));
  905. return;
  906. }
  907. $skins = '';
  908. ob_start();
  909. eval($form_state['values']['skin_configurations']);
  910. ob_end_clean();
  911. foreach ($skins as $key => $skin) {
  912. if (!is_array($skin)) {
  913. form_error($form['skin_configurations'], t('These are not valid skin configurations.'));
  914. break;
  915. }
  916. $skins[$key] = (object) $skin;
  917. if (!skinr_skin_validate($skins[$key])) {
  918. form_error($form['skin_configurations'], t('These are not valid skin configurations.'));
  919. }
  920. }
  921. $form_state['skins'] = &$skins;
  922. }
  923. /**
  924. * Form submission handler for skinr_ui_import_form().
  925. */
  926. function skinr_ui_import_form_submit(&$form, &$form_state) {
  927. foreach ($form_state['skins'] as $skin) {
  928. // Find existing skin configuration and grab its sid.
  929. $params = array(
  930. 'theme' => $skin->theme,
  931. 'module' => $skin->module,
  932. 'element' => $skin->element,
  933. 'skin' => $skin->skin,
  934. );
  935. $sids = skinr_skin_get_sids($params);
  936. if (!empty($sids)) {
  937. $skin->sid = reset($sids);
  938. }
  939. // Save skin configuration.
  940. if (!skinr_skin_save($skin)) {
  941. drupal_set_message(t('Not all skin configurations could be saved!'), 'error', FALSE);
  942. }
  943. }
  944. drupal_set_message(t('The skin configurations have been saved.'));
  945. drupal_goto('admin/structure/skinr');
  946. }
  947. /**
  948. * Form builder for the skinr settings delete confirmation form.
  949. *
  950. * @param $theme
  951. * The name of the theme to delete a setting for.
  952. * @param $module
  953. * The module to delete a setting for.
  954. * @param $element
  955. * The ID of the setting to delete.
  956. *
  957. * @ingroup forms
  958. */
  959. function skinr_ui_delete_confirm($form, &$form_state, $skin) {
  960. $form['#skin'] = $skin;
  961. // Always provide skin configuration sid in the same form key as in the skin
  962. // configuration edit form.
  963. $form['sid'] = array(
  964. '#type' => 'value',
  965. '#value' => $skin->sid,
  966. );
  967. $themes = list_themes();
  968. return confirm_form($form,
  969. t('Are you sure you want to delete this skin configuration?'),
  970. isset($_GET['destination']) ? $_GET['destination'] : 'admin/structure/skinr',
  971. t('This action cannot be undone.<br />Theme: %theme<br />Module: %module<br />Element: %element<br />Skin: %skin', array('%theme' => $themes[$skin->theme]->info['name'], '%module' => $skin->module, '%element' => $skin->element, '%skin' => $skin->skin)),
  972. t('Delete'),
  973. t('Cancel')
  974. );
  975. }
  976. /**
  977. * Form submission handler for skinr_ui_delete_confirm().
  978. */
  979. function skinr_ui_delete_confirm_submit($form, &$form_state) {
  980. if ($form_state['values']['confirm']) {
  981. skinr_skin_delete($form_state['values']['sid']);
  982. watchdog('content', 'Deleted a skin configuration.');
  983. drupal_set_message(t('A skin configuration has been deleted.'));
  984. }
  985. $form_state['redirect'] = 'admin/structure/skinr';
  986. }