? quicktabs_ctools_export.patch Index: quicktabs.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/quicktabs/quicktabs.install,v retrieving revision 1.4.2.11 diff -u -p -r1.4.2.11 quicktabs.install --- quicktabs.install 10 Jan 2010 01:06:40 -0000 1.4.2.11 +++ quicktabs.install 26 May 2010 13:24:14 -0000 @@ -7,14 +7,24 @@ function quicktabs_schema() { $schema['quicktabs'] = array( 'description' => 'The quicktabs table.', + // Optional CTools export.inc integration + 'export' => array( + 'key' => 'qtid', + 'identifier' => 'quicktabs', + 'default hook' => 'quicktabs_default_quicktabs', + 'api' => array( + 'owner' => 'quicktabs', + 'api' => 'quicktabs', + 'minimum_version' => 1, + 'current_version' => 1, + ), + ), 'fields' => array( 'qtid' => array( 'description' => 'The primary identifier for a qt block.', - 'type' => 'serial', - 'unsigned' => TRUE, - 'size' => 'big', + 'type' => 'varchar', + 'length' => 255, 'not null' => TRUE, - 'disp-width' => '10', ), 'ajax' => array( 'description' => 'Whether this is an ajax views block.', @@ -215,3 +225,41 @@ function quicktabs_update_6206() { return $ret; } +/** + * Migrate existing quicktabs over to new schema. + */ +function quicktabs_update_6207() { + $ret = array(); + + // Pull all existing quicktabs, and then delete existing quicktabs. We will reinsert. + $result = db_query("SELECT * FROM {quicktabs}"); + $ret[] = update_sql("DELETE FROM {quicktabs}"); + + db_drop_field($ret, 'quicktabs', 'qtid'); + $new_field = array( + 'description' => 'The primary identifier for a qt block.', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + ); + db_add_field($ret, 'quicktabs', 'qtid', $new_field); + db_add_primary_key($ret, 'quicktabs', array('qtid')); + + $used = array(); + while ($row = db_fetch_array($result)) { + // Generate a machine-readable string + $qtid = strtolower(preg_replace('/[^a-zA-Z0-9_]+/', '_', $row['title'])); + $i = 0; + while (in_array($i == 0 ? $qtid : "{$qtid}_{$i}", $used)) { + $i++; + } + $row['qtid'] = $i == 0 ? $qtid : "{$qtid}_{$i}"; + + $placeholders = implode(', ', array_keys($row)); + $tokens = implode(', ', array_fill(0, count($row), "'%s'")); + db_query("INSERT INTO {quicktabs} ($placeholders) VALUES($tokens)", $row); + + $ret[] = "Converted quicktab {$row['qtid']}."; + } + return $ret; +} Index: quicktabs.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/quicktabs/quicktabs.module,v retrieving revision 1.10.2.80 diff -u -p -r1.10.2.80 quicktabs.module --- quicktabs.module 8 May 2010 22:38:26 -0000 1.10.2.80 +++ quicktabs.module 26 May 2010 13:24:15 -0000 @@ -69,8 +69,8 @@ function quicktabs_menu() { 'type' => MENU_LOCAL_TASK, 'file' => 'includes/admin.inc', ); - $items['admin/build/quicktabs/%quicktabs/edit'] = array( - 'title' => 'Edit QT block', + $items['admin/build/quicktabs/%quicktabs'] = array( + 'title' => 'Edit', 'page callback' => 'drupal_get_form', 'page arguments' => array('quicktabs_form', 'edit', 3), 'access arguments' => array('administer quicktabs'), @@ -78,22 +78,38 @@ function quicktabs_menu() { 'type' => MENU_CALLBACK, 'file' => 'includes/admin.inc', ); + $items['admin/build/quicktabs/%quicktabs/edit'] = array( + 'title' => 'Edit', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('quicktabs_form', 'edit', 3), + 'access arguments' => array('administer quicktabs'), + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'file' => 'includes/admin.inc', + ); $items['admin/build/quicktabs/%quicktabs/delete'] = array( - 'title' => 'Delete QT block', + 'title' => 'Delete', 'page callback' => 'drupal_get_form', 'page arguments' => array('quicktabs_block_delete', 3), 'access arguments' => array('administer quicktabs'), 'load arguments' => array('delete'), - 'type' => MENU_CALLBACK, + 'type' => MENU_LOCAL_TASK, 'file' => 'includes/admin.inc', ); $items['admin/build/quicktabs/%quicktabs/clone'] = array( - 'title' => 'Clone QT block', + 'title' => 'Clone', 'page callback' => 'quicktabs_clone', 'page arguments' => array(3), 'access arguments' => array('administer quicktabs'), 'load arguments' => array('clone'), - 'type' => MENU_CALLBACK, + 'type' => MENU_LOCAL_TASK, + 'file' => 'includes/admin.inc', + ); + $items['admin/build/quicktabs/%quicktabs/export'] = array( + 'title' => 'Export', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('quicktabs_export_form', 3), + 'access arguments' => array('administer quicktabs'), + 'type' => MENU_LOCAL_TASK, 'file' => 'includes/admin.inc', ); @@ -137,10 +153,9 @@ function quicktabs_block($op = 'list', $ switch ($op) { case 'list': $blocks = array(); - $result = db_query('SELECT qtid, title FROM {quicktabs}'); - while ($row = db_fetch_object($result)) { - $blocks[$row->qtid]['info'] = $row->title; - $blocks[$row->qtid]['cache'] = BLOCK_NO_CACHE; + foreach (quicktabs_get_all_quicktabs() as $qtid => $quicktabs) { + $blocks[$qtid]['info'] = $quicktabs['title']; + $blocks[$qtid]['cache'] = BLOCK_NO_CACHE; } return $blocks; break; @@ -463,15 +478,54 @@ function quicktabs_style_options($includ } /** + * Load all from defaults and database quicktabs. + */ +function quicktabs_get_all_quicktabs() { + $quicktabs = array(); + + // Load quicktabs via ctools is present. + if (module_exists('ctools')) { + ctools_include('export'); + $loaded = ctools_export_load_object('quicktabs', 'all'); + foreach ($loaded as $qtid => $quicktab) { + $quicktabs[$qtid] = (array) $quicktab; + } + return $quicktabs; + } + + // Otherwise, load from DB + $result = db_query('SELECT qtid, title FROM {quicktabs} ORDER BY title'); + while ($quicktab = db_fetch_array($result)) { + $quicktabs[$quicktab['qtid']] = _quicktabs_unpack($quicktab); + } + return $quicktabs; +} + +/** * Load the quicktabs data. */ function quicktabs_load($qtid, $op = 'view') { + // Load quicktabs via ctools is present. + if (module_exists('ctools')) { + ctools_include('export'); + $defaults = ctools_export_load_object('quicktabs', 'names', array($qtid)); + return isset($defaults[$qtid]) ? (array) $defaults[$qtid] : FALSE; + } + + // Load quicktabs from the database. $quicktabs = db_fetch_array(db_query('SELECT qtid, title, tabs, ajax, hide_empty_tabs, default_tab, style FROM {quicktabs} WHERE qtid = %d', $qtid)); - if (!$quicktabs) { - return FALSE; + if ($quicktabs) { + return _quicktabs_unpack($quicktabs); } + return FALSE; +} +/** + * Unpack a quicktabs row array from the database. + */ +function _quicktabs_unpack($quicktabs) { $tabs = unserialize($quicktabs['tabs']); + $weight = array(); foreach ($tabs as $key => $tab) { $weight[$key] = $tab['weight']; if ($tab['type'] == 'qtabs' && $tab['qtid'] == $qtid) { Index: includes/admin.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/quicktabs/includes/Attic/admin.inc,v retrieving revision 1.1.2.54 diff -u -p -r1.1.2.54 admin.inc --- includes/admin.inc 20 Apr 2010 18:24:05 -0000 1.1.2.54 +++ includes/admin.inc 26 May 2010 13:24:15 -0000 @@ -5,19 +5,49 @@ * Page callback for quicktabs admin landing page. */ function quicktabs_list() { - $result = db_query('SELECT qtid, title FROM {quicktabs} ORDER BY title'); $header = array( array('data' => t('Quicktab')), - array('data' => t('Operations'), 'colspan' => 3), + array('data' => t('Storage')), + array('data' => t('Operations'), 'colspan' => module_exists('ctools') ? 4 : 3), ); $rows = array(); - while ($row = db_fetch_object($result)) { - $tablerow = array( - array('data' => $row->title), - array('data' => l(t('Edit'), 'admin/build/quicktabs/'. $row->qtid .'/edit')), - array('data' => l(t('Clone'), 'admin/build/quicktabs/'. $row->qtid .'/clone')), - array('data' => l(t('Delete'), 'admin/build/quicktabs/'. $row->qtid .'/delete')), - ); + + foreach (quicktabs_get_all_quicktabs() as $quicktabs) { + if (module_exists('ctools')) { + // Determine storage + switch ($quicktabs['export_type']) { + case EXPORT_IN_DATABASE | EXPORT_IN_CODE: + $storage = t('Overridden'); + $delete = l(t('Revert'), 'admin/build/quicktabs/'. $quicktabs['qtid'] .'/delete'); + break; + case EXPORT_IN_DATABASE: + $storage = t('Normal'); + $delete = l(t('Delete'), 'admin/build/quicktabs/'. $quicktabs['qtid'] .'/delete'); + break; + case EXPORT_IN_CODE: + $storage = t('Default'); + $delete = ''; + break; + } + + $tablerow = array( + array('data' => $quicktabs['title']), + array('data' => $storage), + array('data' => l(t('Edit'), 'admin/build/quicktabs/'. $quicktabs['qtid'] .'/edit')), + array('data' => l(t('Export'), 'admin/build/quicktabs/'. $quicktabs['qtid'] .'/export')), + array('data' => l(t('Clone'), 'admin/build/quicktabs/'. $quicktabs['qtid'] .'/clone')), + array('data' => $delete), + ); + } + else { + $tablerow = array( + array('data' => $quicktabs['title']), + array('data' => t('Normal')), + array('data' => l(t('Edit'), 'admin/build/quicktabs/'. $quicktabs['qtid'] .'/edit')), + array('data' => l(t('Clone'), 'admin/build/quicktabs/'. $quicktabs['qtid'] .'/clone')), + array('data' => l(t('Delete'), 'admin/build/quicktabs/'. $quicktabs['qtid'] .'/delete')), + ); + } $rows[] = $tablerow; } if (!empty($rows)) { @@ -44,12 +74,6 @@ function quicktabs_clone($quicktabs) { function quicktabs_form($form_state, $formtype, $quicktabs = array()) { $form = _qt_admin_main_form($form_state, $quicktabs); - if ($formtype == 'edit') { - $form['qtid'] = array( - '#type' => 'hidden', - '#value' => isset($quicktabs['qtid']) ? $quicktabs['qtid'] : 0, - ); - } $no_tabs = TRUE; if (empty($quicktabs['tabs'])) { $quicktabs['tabs'] = array( @@ -95,6 +119,27 @@ function _qt_admin_main_form($form_state $quicktabs = $form_state['quicktabs'] + (array)$quicktabs; } + if (empty($quicktabs['qtid'])) { + $form['qtid'] = array( + '#title' => t('Quicktabs ID'), + '#type' => 'textfield', + '#description' => t('A unique ID that will be used internally and in the CSS ID of your quicktabs block. must contain only lowercase letters, numbers, and underscores.'), + '#default_value' => '', + '#weight' => -8, + '#required' => TRUE, + ); + } + else { + $form['qtid'] = array('#type' => 'value', '#value' => $quicktabs['qtid']); + $form['qtid_display'] = array( + '#title' => t('Quicktabs ID'), + '#type' => 'item', + '#value' => "{$quicktabs['qtid']}", + '#description' => t('This ID will be used internally by quicktabs and will be used in the CSS ID of your quicktabs block.'), + '#weight' => -8, + ); + } + $form['title'] = array( '#title' => t('Block title'), '#type' => 'textfield', @@ -427,6 +472,12 @@ function quicktabs_ahah() { function quicktabs_form_validate($form, &$form_state) { // We don't want it to validate when we're just adding or removing tabs. if ($form_state['clicked_button']['#id'] == 'edit-submit-form') { + if (empty($form_state['values']['qtid'])) { + form_set_error('qtid', t('The quicktabs ID is required.')); + } + else if (!preg_match('!^[a-z0-9_]+$!', $form_state['values']['qtid'])) { + form_set_error('type', t('The quicktabs ID must contain only lowercase letters, numbers, and underscores.')); + } if (empty($form_state['values']['title'])) { form_set_error('title', t('Title is required for the quicktab block.')); } @@ -459,7 +510,8 @@ function quicktabs_form_submit($form, &$ $quicktabs = _quicktabs_convert_form_to_quicktabs($form_state); drupal_alter('quicktabs', $quicktabs, 'presave'); - if ($quicktabs['qtid'] > 0) { + $exists = quicktabs_load($quicktabs['qtid']); + if ($exists && empty($exists['in_code_only'])) { $ret = drupal_write_record('quicktabs', $quicktabs, 'qtid'); if ($ret == SAVED_UPDATED) { drupal_set_message(t('The quicktab block has been updated.')); @@ -488,13 +540,43 @@ function quicktabs_block_delete(&$form_s * Submit handler for quicktab block deletion. */ function quicktabs_block_delete_submit($form, &$form_state) { - db_query('DELETE FROM {quicktabs} WHERE qtid = %d', $form_state['values']['qtid']); + db_query("DELETE FROM {quicktabs} WHERE qtid = '%s'", $form_state['values']['qtid']); drupal_set_message(t('The quicktab block %name has been removed.', array('%name' => $form_state['values']['qt_name']))); cache_clear_all(); $form_state['redirect'] = 'admin/build/quicktabs'; }; /** + * Export form for quicktabs. + */ +function quicktabs_export_form(&$form_state, $quicktabs) { + ctools_include('export'); + + // Generate export code + $code = '$items = array();' ."\n"; + $code .= ctools_export_object('quicktabs', (object) $quicktabs, ''); + $code .= '$items["'. $quicktabs['qtid'] .'"] = $quicktabs;' ."\n"; + $code .= 'return $items;'; + + // Create form + $form = array(); + $form['export'] = array( + '#type' => 'textarea', + '#default_value' => $code, + '#rows' => substr_count($code, "\n") + 1, + '#resizable' => FALSE, + '#description' => t('Place this code in your module\'s implementation of hook_quicktabs_default_quicktabs() to provide it as a default quicktab.'), + ); + $form['done'] = array( + '#type' => 'submit', + '#value' => t('Done'), + ); + $form['#redirect'] = 'admin/build/quicktabs'; + + return $form; +} + +/** * Callback function for admin/settings/quicktabs. Display the settings form. */ function quicktabs_settings() {