View source
<?php
function sheetnode_node_info() {
return array(
'sheetnode' => array(
'name' => t('Sheetnode'),
'module' => 'sheetnode',
'description' => t('A spreadsheet node.'),
),
);
}
function sheetnode_perm() {
return array(
'create sheetnode',
'edit own sheetnode',
'edit any sheetnode',
'delete own sheetnode',
'delete any sheetnode',
'create sheet template',
'edit sheet settings',
);
}
function sheetnode_access($op, $node, $account = NULL) {
global $user;
if (empty($account)) {
$account = $user;
}
if ($op == 'create') {
return user_access('create sheetnode', $account) ? TRUE : NULL;
}
if ($op == 'update') {
return user_access('edit any sheetnode', $account) || user_access('edit own sheetnode', $account) && $account->uid == $node->uid ? TRUE : NULL;
}
if ($op == 'delete') {
return user_access('delete any sheetnode', $account) || user_access('delete own sheetnode', $account) && $account->uid == $node->uid ? TRUE : NULL;
}
}
function sheetnode_delete(&$node) {
db_query('DELETE FROM {sheetnode} WHERE nid=%d', $node->nid);
}
function sheetnode_form(&$node) {
$type = node_get_types('type', $node);
$form = node_content_form($node, NULL);
$nid = $node->nid;
if (isset($_POST['sheetsave'])) {
$value = $_POST['sheetsave'];
}
else {
if (!empty($node->nid)) {
$value = _sheetnode_load($node->nid, $node->vid);
}
else {
if ($node->clone_from_original_nid) {
$original_node = node_load($node->clone_from_original_nid);
$value = _sheetnode_load($original_node->nid, $original_node->vid);
$nid = $node->clone_from_original_nid;
}
else {
$value = '';
}
}
}
$output = _sheetnode_inject($value, 'edit-sheetsave', array(
'entity-name' => 'node',
'oid' => $nid,
));
$form['sheet']['sheetview'] = array(
'#value' => $output,
'#weight' => -1,
);
$form['sheet']['sheetsave'] = array(
'#type' => 'hidden',
);
if (user_access('create sheet template')) {
$form['template'] = array(
'#type' => 'textfield',
'#title' => t('Save as template'),
'#description' => t('When saving this sheet, also keep a copy under the name you specify here. Later, this copy can be used as a template for other sheets.'),
'#required' => FALSE,
);
}
return $form;
}
function sheetnode_form_alter($form_id, &$form) {
if (isset($form['type']) && isset($form['type']['#value']) && $form['type']['#value'] == 'sheetnode') {
unset($form['preview']);
}
}
function _sheetnode_inject($value, $save_element, $context) {
drupal_add_js(drupal_get_path('module', 'sheetnode') . '/socialcalc/socialcalcconstants.js');
drupal_add_js(drupal_get_path('module', 'sheetnode') . '/socialcalc/socialcalc-3.js');
drupal_add_js(drupal_get_path('module', 'sheetnode') . '/socialcalc/socialcalctableeditor.js');
drupal_add_js(drupal_get_path('module', 'sheetnode') . '/socialcalc/formatnumber2.js');
drupal_add_js(drupal_get_path('module', 'sheetnode') . '/socialcalc/formula1.js');
drupal_add_js(drupal_get_path('module', 'sheetnode') . '/socialcalc/socialcalcpopup.js');
drupal_add_js(drupal_get_path('module', 'sheetnode') . '/socialcalc/socialcalcspreadsheetcontrol.js');
drupal_add_js(drupal_get_path('module', 'sheetnode') . '/socialcalc/socialcalcviewer.js');
drupal_add_js(drupal_get_path('module', 'sheetnode') . '/sheetnode.js');
drupal_add_css(drupal_get_path('module', 'sheetnode') . '/socialcalc/socialcalc.css');
drupal_add_css(drupal_get_path('module', 'sheetnode') . '/sheetnode.css');
module_invoke_all('sheetnode_plugins', $value, $save_element, $context);
static $once = FALSE;
if (!$once) {
$once = TRUE;
drupal_add_js(array(
'sheetnode' => array(
'basePath' => url(),
'value' => $value,
'imagePrefix' => url(drupal_get_path('module', 'sheetnode') . '/socialcalc/images/sc-'),
'containerElement' => 'sheetview',
'saveElement' => $save_element,
'viewMode' => variable_get('sheetnode_view_mode', SHEETNODE_VIEW_FIDDLE),
'showToolbar' => variable_get('sheetnode_view_toolbar', FALSE),
'permissions' => array(
'edit sheet settings' => user_access('edit sheet settings'),
),
'context' => $context,
),
), 'setting');
drupal_add_js('$(document).ready(function() { Drupal.sheetnode.start("body"); });', 'inline');
}
return '<div class="sheetview" id="sheetview"></div>';
}
function _sheetnode_sanitize_js($value) {
$chars = array(
chr(0xe2) . chr(0x80) . chr(0xa8),
);
return str_replace($chars, '', $value);
}
function sheetnode_insert($node) {
if ($node->sheetsave) {
_sheetnode_save($node->nid, $node->vid, $node->sheetsave);
}
if ($node->template && user_access('create sheet template')) {
_sheetnode_template_save($node->vid, $node->template, $node->sheetsave);
}
}
function sheetnode_update($node) {
if (!empty($node->sheetsave)) {
_sheetnode_save($node->nid, $node->vid, $node->sheetsave);
}
else {
if (!empty($node->revision)) {
db_query('INSERT INTO {sheetnode} (nid,vid,value) SELECT old.nid,%d,old.value FROM sheetnode AS old WHERE old.vid=%d', array(
$node->vid,
$node->old_vid,
));
}
}
if (!empty($node->template) && user_access('create sheet template')) {
_sheetnode_template_save($node->vid, $node->template, $node->sheetsave);
}
}
function sheetnode_view($node, $teaser = FALSE, $page = FALSE) {
$node = node_prepare($node, $teaser);
if (!$teaser) {
$value = _sheetnode_load($node->nid, $node->vid);
$output = _sheetnode_inject($value, FALSE, array(
'entity-name' => 'node',
'oid' => $node->nid,
));
$node->content['sheet'] = array(
'#value' => $output,
'#weight' => -1,
);
}
return $node;
}
function sheetnode_nodeapi($node, $op) {
if ($node->type != 'sheetnode') {
return;
}
switch ($op) {
case 'update index':
require_once drupal_get_path('module', 'sheetnode') . '/socialcalc.inc';
$output = '<table>';
$socialcalc = socialcalc_parse(_sheetnode_load($node->nid, $node->vid));
$sc = $socialcalc['sheet'];
$row = -1;
if (!empty($sc['cells'])) {
foreach ($sc['cells'] as $c) {
if ($c['pos'][1] > $row) {
if ($row != -1) {
$output .= '</tr>';
}
$row = $c['pos'][1];
$output .= '<tr>';
}
$output .= '<td>' . (isset($c['datavalue']) ? $c['datavalue'] : ' ') . (isset($c['comment']) ? ' (' . check_plain($c['comment']) . ')' : '') . '</td>';
}
}
if ($row != -1) {
$output .= '</tr>';
}
$output .= '</table>';
return $output;
}
}
function sheetnode_menu($may_cache) {
$items = array();
if ($may_cache) {
$items[] = array(
'path' => 'node/add/sheetnode',
'title' => t('Sheetnode'),
'access' => user_access('create sheetnode'),
);
$items[] = array(
'path' => 'sheetnode/load',
'type' => MENU_CALLBACK,
'callback' => '_sheetnode_ajax_load',
'access' => user_access('access content'),
);
$items[] = array(
'path' => 'sheetnode/field',
'type' => MENU_CALLBACK,
'callback' => '_sheetnode_ajax_field',
'access' => user_access('access content'),
);
$items[] = array(
'path' => 'node/add/sheetnode_template',
'title' => t('Sheetnode import from template'),
'access' => user_access('create sheetnode'),
'callback' => 'drupal_get_form',
'callback arguments' => array(
'sheetnode_import_template',
),
);
$items[] = array(
'path' => 'admin/settings/sheetnode',
'title' => t('Sheetnode'),
'access' => user_access('administer site configuration'),
'callback' => 'drupal_get_form',
'callback arguments' => array(
'sheetnode_admin_settings',
),
);
$items[] = array(
'path' => 'admin/settings/sheetnode/general',
'title' => t('General'),
'access' => user_access('administer site configuration'),
'callback' => 'drupal_get_form',
'callback arguments' => array(
'sheetnode_admin_settings',
),
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
}
return $items;
}
define('SHEETNODE_VIEW_READONLY', 0);
define('SHEETNODE_VIEW_FIDDLE', 1);
define('SHEETNODE_VIEW_HTML', 2);
function sheetnode_admin_settings() {
$form['sheetnode_view_mode'] = array(
'#type' => 'radios',
'#title' => t('View mode'),
'#description' => t('Select the way sheetnodes should be displayed in view mode.'),
'#options' => array(
SHEETNODE_VIEW_READONLY => t('Read-only spreadsheet'),
SHEETNODE_VIEW_FIDDLE => t('Fiddle mode (interactive spreadsheet without save functionality)'),
SHEETNODE_VIEW_HTML => t('HTML table'),
),
'#default_value' => variable_get('sheetnode_view_mode', SHEETNODE_VIEW_FIDDLE),
);
$form['sheetnode_view_toolbar'] = array(
'#type' => 'checkbox',
'#title' => t('Show toolbar in view mode'),
'#default_value' => variable_get('sheetnode_view_toolbar', FALSE),
);
return system_settings_form($form);
}
function sheetnode_import_template() {
$options[0] = t('- Please choose a template -');
$result = db_query("SELECT tid, name FROM {sheetnode_template}");
while ($template = db_fetch_object($result)) {
$options[$template->tid] = $template->name;
}
$form['template'] = array(
'#type' => 'select',
'#title' => t('Template'),
'#description' => t('Please select the template to load into your new sheetnode.'),
'#options' => $options,
'#default_value' => 0,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);
return $form;
}
function sheetnode_import_template_validate($form, $form_values) {
if (!$form_values['template']) {
form_set_error('template', t('Please select a template.'));
}
}
function sheetnode_import_template_submit($form, $form_values) {
global $user;
$template = db_fetch_object(db_query("SELECT * FROM {sheetnode_template} WHERE tid=%d", $form_values['template']));
$node = array(
'type' => 'sheetnode',
'name' => $user->name,
);
$form_state_node = array();
$form_state_node['title'] = $template->name;
$form_state_node['body'] = '';
$form_state_node['name'] = $user->name;
$form_state_node['sheetsave'] = unserialize($template->value);
$result = drupal_execute('sheetnode_node_form', $form_state_node, (object) $node);
return $result . '/edit';
}
function sheetnode_views_api() {
return array(
'api' => 2.0,
);
}
function sheetnode_theme($existing, $type, $theme, $path) {
return array(
'sheetnode_range' => array(
'arguments' => array(
'range' => NULL,
),
),
'sheetfield_spreadsheet' => array(
'arguments' => array(
'element' => NULL,
),
),
'sheetnode_formatter_default' => array(
'arguments' => array(
'element' => NULL,
),
),
'sheetnode_formatter_socialcalc_date' => array(
'arguments' => array(
'element' => NULL,
),
),
);
}
function theme_sheetnode_range($range) {
if (empty($range)) {
return '';
}
require_once drupal_get_path('module', 'sheetnode') . '/socialcalc.inc';
list($c, $r) = socialcalc_coord_to_cr(key($range));
$row = array();
$row[] = array(
'data' => $r,
'header' => TRUE,
);
$header = array();
$header[] = array();
$rows = array();
foreach ($range as $coord => $value) {
$pos = socialcalc_coord_to_cr($coord);
if ($pos[1] > $r) {
$rows[] = $row;
$r = $pos[1];
$row = array();
$row[] = array(
'data' => $r,
'header' => TRUE,
);
}
$row[] = $value;
if (empty($rows)) {
$coord = socialcalc_cr_to_coord($pos[0], $pos[1], TRUE);
$header[] = $coord[0];
}
}
$rows[] = $row;
return theme('table', $header, $rows);
}
function sheetnode_init() {
drupal_add_css(drupal_get_path('module', 'sheetnode') . '/socialcalc/socialcalc.css');
drupal_add_css(drupal_get_path('module', 'sheetnode') . '/sheetnode.css');
}
function sheetnode_content_extra_fields($type_name) {
$extra = array();
if ($type_name == 'sheetnode') {
$extra['sheet'] = array(
'label' => t('Sheetview'),
'description' => t('Sheetnode module form.'),
'weight' => -1,
);
}
return $extra;
}
function sheetnode_field_info() {
return array(
'sheetfield' => array(
'label' => t('Sheet'),
'description' => t('Store a spreadsheet in the database.'),
),
);
}
function sheetnode_field_settings($op, $field) {
switch ($op) {
case 'form':
break;
case 'save':
break;
case 'database columns':
require_once drupal_get_path('module', 'sheetnode') . '/sheetnode.install';
$schema = sheetnode_schema();
$columns['value'] = $schema['sheetnode']['fields']['value'];
return $columns;
case 'views data':
break;
}
}
function sheetnode_field($op, &$node, $field, &$items, $teaser, $page) {
switch ($op) {
case 'insert':
case 'update':
break;
}
}
function sheetnode_content_is_empty($item, $field) {
return FALSE;
}
function sheetnode_field_formatter_info() {
return array(
'default' => array(
'label' => t('Default'),
'field types' => array(
'sheetfield',
),
'multiple values' => CONTENT_HANDLE_CORE,
),
'socialcalc_date' => array(
'label' => t('SocialCalc'),
'field types' => array(
'date',
'datetime',
'datestamp',
),
'multiple values' => CONTENT_HANDLE_CORE,
),
);
}
function sheetnode_widget_info() {
return array(
'sheetfield_spreadsheet' => array(
'label' => t('Spreadsheet'),
'field types' => array(
'sheetfield',
),
'multiple values' => CONTENT_HANDLE_CORE,
'callbacks' => array(
'default value' => CONTENT_CALLBACK_DEFAULT,
),
),
);
}
function sheetnode_widget_settings($op, $widget) {
switch ($op) {
case 'form':
break;
case 'save':
break;
}
}
function sheetnode_widget(&$form, &$form_state, $field, $items, $delta = 0) {
$element = array(
'#type' => $field['widget']['type'],
'#default_value' => isset($items[$delta]) ? $items[$delta] : '',
);
return $element;
}
function sheetnode_elements() {
return array(
'sheetfield_spreadsheet' => array(
'#input' => TRUE,
'#columns' => array(
'value',
),
'#delta' => 0,
'#process' => array(
'sheetfield_spreadsheet_process',
),
'#autocomplete_path' => FALSE,
),
);
}
function sheetfield_spreadsheet_process($element, $edit, $form_state, $form) {
$field_key = $element['#columns'][0];
$delta = $element['#delta'];
$value = isset($element['#default_value']) ? is_array($element['#default_value']) ? $element['#default_value']['value'] : $element['#default_value'] : (isset($element['#value'][$field_key]) && is_string($element['#value'][$field_key]) ? $element['#value'][$field_key] : '');
$output = _sheetnode_inject($value, $element['#id'] . '-' . $field_key, isset($form['#node']) ? array(
'entity-name' => 'node',
'oid' => $form['#node']->nid,
) : NULL);
$element['sheetview'] = array(
'#value' => $output,
'#weight' => -1,
);
$element[$field_key] = array(
'#type' => 'hidden',
);
$element['#tree'] = TRUE;
return $element;
}
function theme_sheetfield_spreadsheet($element) {
return theme('form_element', $element, $element['#children']);
}
function theme_sheetnode_formatter_default($element) {
$value = $element['#item']['value'];
$output = _sheetnode_inject($value, FALSE, isset($element['#node']) ? array(
'entity-name' => 'node',
'oid' => $element['#node']->nid,
) : NULL);
return $output;
}
function theme_sheetnode_formatter_socialcalc_date($element) {
require_once drupal_get_path('module', 'sheetnode') . '/socialcalc.inc';
$field_name = $element['#field_name'];
$fields = content_fields();
$field = $fields[$field_name];
$item = $element['#item'];
$value = $item['value'];
if ($field['type'] == DATE_ISO) {
$value = str_replace(' ', 'T', date_fuzzy_datetime($value));
}
$date = date_make_date($value, NULL, $field['type'], $field['granularity']);
return socialcalc_import_date($date);
}
function _sheetnode_ajax_load($sheetname = NULL, $vid = NULL) {
require_once drupal_get_path('module', 'sheetnode') . '/socialcalc.inc';
if (empty($sheetname)) {
$sheetname = $_REQUEST['sheetname'];
}
if (is_numeric($sheetname)) {
$value = db_result(db_query("SELECT value FROM {sheetnode} WHERE nid=%d ORDER BY vid DESC LIMIT 1", intval($sheetname)));
}
else {
$value = db_result(db_query("SELECT value FROM {sheetnode} s INNER JOIN {node} n ON s.nid=n.nid WHERE UCASE(n.title)='%s' ORDER BY s.vid DESC LIMIT 1", db_escape_string(strtoupper($sheetname))));
}
if (!$value && module_exists('content')) {
if (is_numeric($sheetname)) {
$node = node_load(intval($sheetname));
if ($node) {
$type = content_types($node->type);
foreach ($type['fields'] as $field_name => $field_info) {
if ($field_info['type'] == 'sheetfield' && isset($node->{$field_name})) {
$value = $node->{$field_name}[0]['value'];
}
}
}
}
}
if (!$value && module_exists('views')) {
$view = views_get_view($sheetname);
if ($view) {
foreach (array_keys($view->display) as $display_name) {
$display = $view->display[$display_name];
if (isset($display->display_options['style_plugin']) && $display->display_options['style_plugin'] == 'sheet_raw') {
$value = $view
->render($display->id);
header('Content-type: text/html');
}
}
}
}
if ($value) {
$parts = socialcalc_parse_parts($value);
if (isset($parts['sheet'])) {
echo $parts['sheet'];
}
}
exit;
}
function _sheetnode_ajax_field($oid = NULL, $entity = NULL, $field = NULL) {
if (!$oid) {
$oid = $_REQUEST['oid'];
}
if (!$entity) {
$entity = $_REQUEST['entity'];
}
if (!$field) {
$field = $_REQUEST['field'];
}
if (function_exists($entity . '_load')) {
$object = call_user_func($entity . '_load', $oid);
$value = NULL;
if ($object) {
if ($entity == 'node' && module_exists('content')) {
$field_info = content_fields($field, $object->type);
if ($field_info) {
$field_info['display_settings']['label']['format'] = 'hidden';
$value = content_view_field($field_info, $object, FALSE, TRUE);
}
}
if (!$value && $entity == 'node') {
$node = drupal_clone($object);
$node = node_build_content($node);
if (isset($node->content[$field])) {
$value = drupal_render($node->content[$field]);
}
}
if (!$value && isset($object->{$field})) {
if (is_object($object->{$field}) || is_array($object->{$field})) {
$value = print_r($object->{$field}, TRUE);
}
else {
$value = $object->{$field};
}
}
if ($value) {
_sheetnode_json(array(
'type' => is_numeric($value) ? 'n' : 'th',
'value' => $value,
));
exit;
}
}
}
_sheetnode_json(array(
'value' => '',
'type' => 'e#NAME?',
));
exit;
}
function _sheetnode_json($var = NULL) {
drupal_set_header('Content-Type: text/javascript; charset=utf-8');
if (isset($var)) {
echo drupal_to_js($var);
}
}
function _sheetnode_load($nid, $vid) {
$value = db_result(db_query("SELECT value FROM {sheetnode} WHERE nid=%d AND vid=%d", $nid, $vid));
return $value ? unserialize($value) : '';
}
function _sheetnode_save($nid, $vid, $value) {
db_query("DELETE FROM {sheetnode} WHERE vid=%d", $vid);
db_query("INSERT INTO {sheetnode} (nid, vid, value) VALUES (%d, %d, '%s')", $nid, $vid, serialize(_sheetnode_sanitize_js($value)));
}
function _sheetnode_template_save($vid, $name, $value) {
db_query("DELETE FROM {sheetnode_template} WHERE vid=%d", $vid);
db_query("INSERT INTO {sheetnode_template} (vid, name, value) VALUES (%d, '%s', '%s')", $vid, db_escape_string($name), serialize(_sheetnode_sanitize_js($value)));
}
function _sheetnode_sanitize_filename($filename, $extension) {
$filename = preg_replace('/[^a-zA-Z0-9-_.]/', '-', $filename);
$filename .= '.' . $extension;
return $filename;
}