Common subdirectories: video_upload\CVS and video_upload_browser\CVS
Common subdirectories: video_upload\images and video_upload_browser\images
Common subdirectories: video_upload\providers and video_upload_browser\providers
Common subdirectories: video_upload\tests and video_upload_browser\tests
diff -upN video_upload\video_upload.browser.inc video_upload_browser\video_upload.browser.inc
--- video_upload\video_upload.browser.inc	Mon May 17 02:36:05 2010
+++ video_upload_browser\video_upload.browser.inc	Mon May 17 02:38:12 2010
@@ -1,357 +1,142 @@
 <?php
-
-// $Id: video_upload.browser.inc,v 1.1 2008/10/10 19:02:57 jhedstrom Exp $
+// $Id: video_upload.browser.inc,v 1.1.6.4 2010/05/16 12:44:03 bojanz Exp $
 
 /**
  * @file video_upload.browser.inc
- *   Provides functions for the Browser upload method.
- *   @todo (Works for 5.x, but not yet in 6.x)
+ * Provides functions for the Browser upload method.
  */
 
 /**
- * Prepare form for the browser upload method (video transmitted
- * directly to 3rd party from the browser).
+ *  Build the element.
+ *
+ *  Called from video_upload_field_widget_process().
  */
-function _video_upload_browser_method_widget(&$form, &$form_state, $field, $items, $delta) {
-  // set form class (the jquery depends on this), and encoding type
-  $form['#attributes'] = array(
-    'class' => 'video-upload',
-    'enctype' => 'multipart/form-data',
-  );
+function video_upload_browser_method_field_widget_process($element, &$form_state, $form) {
+  if (empty($element['#value']['video_id'])) {
+    // No video ID yet, present the upload button.
+    $element['video_notification'] = array(
+      '#markup' => '<noscript> <div class="video-upload-browser-noscript">' . t('You need to have JavaScript enabled in order to upload a video.') . '</div> </noscript>'                            
+    );
+    
+    $element['video_browser_upload'] = array(
+      '#type' => 'button',
+      '#value' => t('Launch the Uploader'),
+      '#attributes' => array('class' => array('video-upload-browser-upload'),
+                             'style' => 'display:none'),
+    );
+  }
+  else {
+    // Video thumbnail, status, remove button.
+    $element['video_item'] = array(
+      '#markup' => _video_upload_browser_method_form_item($element['#value'], $element['#id']),
+    );
+  }
 
-  $element = _video_upload_browser_widget_form($form['#node'], $field, $items);
   return $element;
-  switch ($op) {
-    case 'prepare form values' :
-      _video_upload_widget_browser_prepare_form_values($node, $field, $items);
-      break;
-
-    case 'process form values':
-      _video_upload_widget_browser_process_form_values($node, $field, $items);
-      break;
-
-    case 'form' :
-      return _video_upload_browser_widget_form($node, $field, $items);
-
-    case 'validate' :
-      // this doesn't work yet
-      _video_upload_browser_widget_validate($node, $field, $items);
-      break;
-
-    case 'submit' :
-      break;
-
-    case 'default value' :
-      return array(
-        array(
-          'id' => '0',
-          'status' => VIDEO_UPLOAD_STATUS_UNKNOWN,
-          'status_ts' => '',
-          'fid' => '',
-          // @todo see other inline delete todo items
-          // 'delete' => 0,
-        ),
-      );
-      break;
-  }
-  return;
 }
 
 /**
- * Depending on if $node_field contains a YouTube ID or not, the form returned
- * will be drastically different.
- * @param boolean $save
- *   This is only passed when rendering the form from 
+ * Here we render a video widget,
  */
-function _video_upload_browser_widget_form(&$node, $field, &$items) {
-  $field_name = $field['field_name'];
-
-  // this will be set to false if a video already exists on the field,
-  // and multiple uploads aren't allowed.
-  $generate_upload_form = true;
-
-  $form[$field_name] = array(
-    '#type' => 'fieldset',
-    '#title' => t($field['widget']['label']),
-    '#weight' => $field['widget']['weight'],
-    '#description' => t('<strong>Note</strong>: Uploaded videos will not be saved until this post has been saved.'),
-    '#collapsible' => TRUE,
-    '#collapsed' => FALSE,
-    '#tree' => TRUE,
-    '#prefix' => '<div id="'. form_clean_id($field_name . '-attach-wrapper') . '" >',
-    '#suffix' => '</div>',
+function _video_upload_browser_method_form_item($item, $element_id) {  
+  $variables = array(
+    'display' => array(
+      'thumb_width' => 120,
+      'thumb_height' => 74,
+    ),
+    'item' => $item,
+    'path' => ''
   );
-
-  $form[$field_name][0]['id'] = array(
-    '#type' => 'hidden',
-    '#value' => $items[0]['id'],
-  );
-
-  // Attempt a preview (won't show much on adding) for videos
-  // that have an id, and have been confirmed
-  if ($items[0]['id']) {
-    if ($items[0]['status'] > VIDEO_UPLOAD_STATUS_UNKNOWN) {
-      $form[$field_name][0]['preview'] = array(
-        '#type' => 'markup',
-        '#value' => theme('video_upload_video', $items[0]['id'], $field['widget']['display']['small_width'], $field['widget']['display']['small_height']),
-        '#suffix' => t('Use the form below to replace this video with a different one.'),
-      );
-    }
-    elseif ($items[0]['status'] === VIDEO_UPLOAD_STATUS_UNKNOWN) {
-      $form[$field_name][0]['preview'] = array(
-        '#type' => 'markup',
-        '#value' => '<div class="messages">' . t('Video is processing...') . '</div>',
-      );
-    }
-    // @todo make this work (see todo in form processing step for
-    // some initial work
-
-    // $form[$field_name][0]['delete'] = array(
-    //   '#type' => 'checkbox',
-    //   '#title' => t('Delete video ID %id from YouTube', array('%id' => $items[0]['id'])),
-    // );
-  }
-
-  // include Drupal js for dynamic upload handling
-  //  drupal_add_js('misc/progress.js');
-  // drupal_add_js('misc/upload.js');
-  drupal_add_js(drupal_get_path('module', 'video_upload') . '/video_upload.js');
-
-  $form[$field_name]['new'] = array(
-    '#tree' => FALSE,
-    '#prefix' => '<div id="' . form_clean_id($field_name .'-attach-hide') . '">',
-    '#suffix' => '</div>',
-    '#weight' => 100,
-  );
-
-  // youtube expects the POST variable to be named "file"
-  if (!empty($field['widget']['file_extensions'])) {
-    $allowed_extensions = t('<br />Allowed file types: <strong>@types</strong>', array('@types' => $field['widget']['file_extensions']));
-    // format for accept attribute below, the attribute gets used
-    // by video_upload.js as a regex pattern, thus the '|' separator
-    $allowed_types = implode('|', array_filter(explode(' ', $field['widget']['file_extensions'])));
-  }
   
-  // overwrite warning
-  if (!$field['multiple'] && $items[0]['id']) {
-    $overwrite_warning = t('<strong>WARNING</strong>: Uploading another video will overwrite the above video (and be rejected if it is a duplicate).');
-
-    // @todo the delete widget must work first
-    // $generate_upload_form = FALSE;
-  }
-
+  $status_text = theme('video_upload_status_text', $item['video_status']);
+  $thumb = theme('video_upload_video_thumb', $variables);
   
-  // If the browser upload method is being used, we construct an upload form
-  // to YouTube
-  if ($generate_upload_form && $field['widget']['use_browser_upload_method']) {
-    
-    drupal_add_js(drupal_get_path('module', 'video_upload') . '/video_upload_browser.js');
-    
-    // authenticate to youtube
-    if ($http_client = _video_upload_authenticate_youtube()) {
-      
-      // The following is taken and modified from
-      // http://code.google.com/apis/youtube/developers_guide_php.html
-      // @todo perhaps store in SESSION...perhaps not
-      $yt = _video_upload_youtube($http_client);
-      
-      // create a Zend_Gdata_YouTube_VideoEntry
-      $video = _video_upload_video_entry();
-      
-      // set up media group
-      _video_upload_construct_media_group($yt, $video, $node, $field);
-      
-      $token_array = _video_upload_get_token_array($yt, $video);
-      
-      // Set action to YouTube @todo this will need to be done in order for
-      // this to work w/o js enabled and then have the js re-construct the
-      // action back to this site 
-      // $form['#action'] = url($token_array['url'], 'nexturl=' . _video_upload_get_next_url());
-      
-      if ($token_array) {
-        // Set youtube as the upload destination, which will then redirect to
-        // the js callback url. The dynamic behavior is triggered by setting
-        // the class to "upload"
-        
-        // token
-        $form[$field_name]['new']['token'] = array(
-          '#type' => 'hidden',
-          // YouTube requires the name to be 'token'
-          '#name' => 'token',
-          '#value' => $token_array['token'],
-        );
-        // this gets changed, as YouTube redirects to the video_upload ajax
-        // handler
-        $ajax_form_submit_url = url($token_array['url'], array('query' => 'nexturl=' . urlencode(_video_upload_get_next_url($field_name, $node))));
-      }
-      else {
-        // can't generate upload form w/o a token
-        $generate_upload_form = false;
-        $auth_error = true;
-        watchdog('video_upload', t('Authentication to YouTube succeeded, but failed to generate a token'), WATCHDOG_ERROR);
-      }
-    }
-    else {
-      // auth error will provide a warning
-      $auth_error = true;
-      $generate_upload_form = false;
-    }
-
-    if ($auth_error) {
-      $form[$field_name]['holder'] = array(
-        '#type' => 'markup',
-        '#value' => t('Video Uploads currently unavailable. Please try back soon'),
-      );
-    }
-  }
-  elseif ($generate_upload_form) {
-    // The Direct Upload method transfers the file here first
-
-    // Submission to YouTube is handled later, send file here
-    $ajax_form_submit_url = _video_upload_get_next_url($field_name, $node);
-
-    foreach ($items as $delta => $item) {
-      if ($item['fid']) {
-        $form[$field_name][$delta]['fid'] = array(
-          '#type' => 'hidden',
-          '#value' => $item['fid'],
-        );
-      }
-    }  
-  }
-
-  if ($generate_upload_form) {
-    // Note, youtube requires that this field be called 'file', but the Drupal
-    // Form API doesn't work with renaming of this field. Since Browser
-    // uploads only work with js enabled, this field is renamed properly
-    // client side when the user attempts a YouTube upload.
-    $form[$field_name]['new'][$field_name . '_file'] = array(
-      '#type' => 'file',
-      '#description' =>  $overwrite_warning . $field['widget']['description'] . $allowed_extensions,
-      '#title' => t('File'),
-      '#tree' => FALSE,
-      '#attributes' => array(
-        'class' => 'video-upload-file video-upload video-upload-' . form_clean_id($field_name),
-        // browsers tend not to enforce this, but some javascript can
-        'accept' => $allowed_types,
-        'id' => 'blaz',
-      ),
-    );
-  }
-
-  if ($generate_upload_form) {
-    // The dynamic behavior of the form is triggered by the 'upload' and
-    // 'video-upload-url' classes.
-    $form[$field_name .'-attach-url'] = array(
-      '#type' => 'hidden', 
-      '#value' => $ajax_form_submit_url, 
-      '#attributes' => array('class' => 'upload video-upload-url')
-    );
+  $markup = '<div id="' . $element_id . '-browser-item" class="video-upload-browser-item">';
   
-    // button
-    $form[$field_name]['new']['submit'] = array(
-      '#type' => 'button',
-      '#value' => t('Upload Video File'),
-      '#id' => form_clean_id($field_name . '-attach-button'),
-      '#attributes' => array(
-      'class' => 'video-upload video-upload-submit',
-      ),
-    );
-  }
-
-  return $form;
+  $markup .= '<div class="video-upload-browser-item-left">';
+  $markup .= '<a href="http://www.youtube.com/v/' . $item['video_id'] . '">' . $thumb . '</a>';
+  $markup .= '</div>';
+  
+  $markup .= '<div class="video-upload-browser-item-right">';
+  $markup .= 'Status: ' . $status_text;
+  $markup .= '<br /> <button class="form-submit video-upload-browser-delete" id="' . $element_id . '-video-browser-delete">Remove</button>';
+  $markup .= '</div>';
+  $markup .= '<div class="video-upload-clearer">&nbsp</div>';
+  
+  $markup .= '</div>';
+  
+  return $markup;
 }
 
-/**
- * Validate a set of items
- */
-function _video_upload_browser_widget_validate(&$node, $field, &$items) {
-  if ($field['required']) {
-    if ($field['widget']['use_browser_upload_method']) {
-      // if using the browser upload method, we need a YouTube ID
-      if (!$items[0]['id']) {
-        $error = true;
-      }
-    }
-    else {
-      // for the direct upload method, we need a file
-      if (!$items[0]['fid']) {
-        $error = true;
-      }
-    }
-    if ($error) {
-      form_set_error($field['field_name'], t('@field is required. Please select a video and hit the <em>Upload Video File</em> button.', array('@field' => $field['widget']['label'])));
-    }
-  }
+function video_upload_browser_method_add_static() {
+  drupal_add_js(drupal_get_path('module', 'video_upload') .'/video_upload_browser.js');
+  drupal_add_css(drupal_get_path('module', 'video_upload') .'/video_upload_browser.css');
+  
+  drupal_add_library('system', 'ui.dialog');
+  drupal_add_library('system', 'ui.draggable');
+  drupal_add_library('system', 'ui.resizable');
+  
+  drupal_add_css("misc/ui/jquery.ui.dialog");
 }
 
 /**
- * Prepare data for form
+ * Callback. This is the page that youtube redirects to.
+ * The reponse goes to an iframe and gets parsed.
  */
-function _video_upload_browser_widget_prepare_form_values(&$node, $field, &$items) {
-  if (!count($_POST)) {
-    // start fresh if no post datas
-    video_upload_clear_session_data();
-  }
-
-  $field_name = $field['field_name'];
-
-  // @fixme - This need to be reviewed. The reason this is required
-  //          is that the Drupal Form API doesn't allow js to change
-  //          the values of hidden variables, so it must be done here.
-  //          Supposedly it is dangerous to do so, thus the need for a
-  //          review.
-  // @fixme - This won't work once multiple items are in play
-  if ($_POST[$field_name][0]['id']) {
-    $node->{$field_name}[0]['id'] = $_POST[$field_name][0]['id'];
-    $items[0]['id'] = $node->{$field_name}[0]['id'];
-  }
+function video_upload_browser_method_success() {
+  $value = array('video_id' => $_GET['id'],
+                 'video_status' => 'unkown');
+  
+  $status = array('id' => $_GET['id'],
+                  'success' => ($_GET['status'] == '200') ? TRUE : FALSE,
+                  'field' => _video_upload_browser_method_form_item($value, '$element_id'),
+                  );
+  
+  print drupal_json_encode($status);
+  exit;
+}
 
-  // Check for file uploaded to local server
-  if ($file = file_check_upload($field_name . '_file')) {
-    $valid = _video_upload_widget_validate_video_file($node, $field, $items, $file);
-    if ($valid) {
-      _video_upload_upload_video_file($node, $field, $items, $file);
-    }
-    else {
-      // @todo delete the invalid image
-    }
-  }
+function video_upload_browser_method_dialog() {
+  $form = drupal_get_form('video_upload_browser_method_upload_form');
+  
+  echo drupal_render($form);
+  exit;
 }
 
-/**
- * Convert back to native storage
- */
-function _video_upload_browser_widget_process_form_values(&$node, $field, &$items) {
-  foreach ($items as $delta => $item) {
+function video_upload_browser_method_upload_form() {
+  $element_id = arg(2);
 
-    if ($item['id'] && !$item['status']) {
-      // @todo make this work
-      if (false && $item['delete'] && $item['id']) {
-        // delete video from youtube
-        _video_upload_delete(array($item), $field);
-        $item['id'] = '';
-        $item['delete'] = 0;
-      }
-      if ($status = video_upload_youtube_validate($item['id'], $node)) {
-        $item['status'] = $status->status;
-        $item['status_ts'] = time();
-      }
-      $items[$delta] = $item;
-    }
-  }
-}
+  video_upload_initialize_provider();
+  
+  // authenticate to youtube
+  $http_client = _video_upload_authenticate_youtube();
+  
+  $youtube = _video_upload_youtube($http_client);
+  $video = _video_upload_video_entry();
+  _video_upload_construct_media_group($youtube, $video, array(), array());
+  
+  $token_array = _video_upload_get_token_array($youtube, $video);
+  
+  $form['#action'] = $token_array['url'] .= '?nexturl=' . url('video-upload/success', array('absolute' => TRUE));
+  $form['#attributes']['enctype'] = 'multipart/form-data';
+  
+  $form['element_id'] = array(
+    '#type' => 'hidden',
+    '#value' => $element_id,
+  );
+  
+  // youtube upload token
+  $form['token'] = array(
+    '#type' => 'hidden',
+    '#name' => 'token',
+    '#value' => $token_array['token'],
+  );
+  
+  $form['upload'] = array(
+    '#type' => 'file',
+    '#title' => t('Please select'),
+    '#size' => 35,
+  );
 
-/**
- * Get the url that youtube will redirect to
- * @param string $field_name
- * @param object $node
- * @return string
- */
-function _video_upload_get_next_url($field_name, $node) {
-  global $base_url;
-  // the field name is passed as part of the path because the YouTube API
-  // doesn't handle encoded urls, and submitting a ? in the url doesn't work
-  // properly
-  return url('video-upload/js/' . $field_name . '/' . $node->type, array('absolute' => TRUE));
-}
+  return $form;
+}
\ No newline at end of file
diff -upN video_upload\video_upload.field.inc video_upload_browser\video_upload.field.inc
--- video_upload\video_upload.field.inc	Thu Apr 29 03:52:26 2010
+++ video_upload_browser\video_upload.field.inc	Mon May 17 02:33:15 2010
@@ -126,6 +126,7 @@ function video_upload_field_widget_info(
   );
   $video['video_upload_widget']['settings'] = $file['file_generic']['settings'];
   $video['video_upload_widget']['settings'] += array(
+    'use_browser_upload_method' => FALSE,
     'video_category' => '',
     'auto_delete_rejected_videos' => 0,
     'remove_deleted_videos' => 0,
@@ -166,7 +167,25 @@ function video_upload_field_widget_form(
   $elements = file_field_widget_form($form, $form_state, $field, $instance, $langcode, $items, $delta, $element);
 
   foreach (element_children($elements) as $delta) {
+    if ($instance['widget']['settings']['use_browser_upload_method']) {
+      $elements[$delta]['#process'] = array(
+        'video_upload_field_widget_process',
+        'video_upload_browser_method_field_widget_process'
+      );
+      
+      $elements[$delta]['#upload_validators'] = array();
+      $elements[$delta]['#value_callback'] = '';
+      $elements[$delta]['#description'] = $instance['description'];
+      
+      continue;
+    }
+  
     $elements[$delta]['#process'][] = 'video_upload_field_widget_process';
+  }
+  
+  if ($instance['widget']['settings']['use_browser_upload_method']) {
+    // add the css and js files needed (jquery_ui and our own)
+    video_upload_browser_method_add_static();
   }
 
   return $elements;
diff -upN video_upload\video_upload.info video_upload_browser\video_upload.info
--- video_upload\video_upload.info	Mon May 17 02:36:05 2010
+++ video_upload_browser\video_upload.info	Sun May 16 23:28:24 2010
@@ -9,4 +9,5 @@ files[] = video_upload.field.inc
 files[] = video_upload.install
 files[] = video_upload.widget.inc
 files[] = video_upload.admin.inc
+files[] = video_upload.browser.inc
 files[] = tests/video_upload.test
diff -upN video_upload\video_upload.module video_upload_browser\video_upload.module
--- video_upload\video_upload.module	Mon May 17 02:36:05 2010
+++ video_upload_browser\video_upload.module	Mon May 17 02:37:06 2010
@@ -12,6 +12,7 @@
 // Load all Field module hooks for Video Upload.
 module_load_include('inc', 'video_upload', 'video_upload.field');
 module_load_include('inc', 'video_upload', 'video_upload.widget');
+module_load_include('inc', 'video_upload', 'video_upload.browser');
 
 /**
  * Video status levels.
@@ -131,6 +132,23 @@ function video_upload_menu() {
     'access arguments' => array('administer uploaded videos'),
     'file' => 'video_upload.admin.inc',
     'description' => 'Manage all uploaded videos.',
+  );
+  
+  // Browser method callbacks
+  $items['video-upload/dialog'] = array(
+    'title' => 'Get the form for the browser upload dialog',
+    'page callback' => 'video_upload_browser_method_dialog',
+    'access arguments' => array('access content'),
+    'file' => 'video_upload.browser.inc',
+    'type' => MENU_CALLBACK,
+  );
+    
+  $items['video-upload/success'] = array(
+    'title' => 'YouTube Browser Upload final callback',
+    'page callback' => 'video_upload_browser_method_success',
+    'access arguments' => array('access content'),
+    'file' => 'video_upload.browser.inc',
+    'type' => MENU_CALLBACK,
   );
 
   return $items;
diff -upN video_upload\video_upload.widget.inc video_upload_browser\video_upload.widget.inc
--- video_upload\video_upload.widget.inc	Sun May 16 21:59:15 2010
+++ video_upload_browser\video_upload.widget.inc	Sun May 16 23:33:07 2010
@@ -19,6 +19,13 @@ function _video_upload_field_widget_sett
   $settings = $widget['settings'];
   video_upload_initialize_provider();
   $form = module_invoke('file', 'field_widget_settings_form', $field, $instance);
+  
+  $form['use_browser_upload_method'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Use the Browser Upload method'),
+    '#default_value' => $settings['use_browser_upload_method'],
+    '#description' => t('The <a href="!url">Browser Upload method</a> sends video files directly to YouTube, instead of touching the Drupal server. This saves on storage and bandwidth', array('!url' => url('http://code.google.com/apis/youtube/developers_guide_php.html#BrowserUpload'))),
+  );
 
   // Maintenance.
   $form['auto_delete_rejected_videos'] = array(
diff -upN video_upload\video_upload_browser.css video_upload_browser\video_upload_browser.css
--- video_upload\video_upload_browser.css	Thu Jan 01 01:00:00 1970
+++ video_upload_browser\video_upload_browser.css	Fri May 14 20:45:52 2010
@@ -0,0 +1,49 @@
+/* $Id: video_upload_browser.css,v 1.1.2.2 2010/05/14 18:45:52 bojanz Exp $ */
+
+/**
+ * @file
+ * CSS for the Video Upload Browser method.
+ */
+.video-upload-browser-item-left {
+  float: left;
+}
+
+.video-upload-browser-item-right {
+  float: left;
+  margin-left: 15px;
+  height: 74px;
+}
+
+.video-upload-clearer {
+  clear:both;
+  height:0;
+}
+
+.video-upload-browser-upload {
+  margin: 0.5em 0.5em 0.5em 0 !important;
+}
+
+.video-upload-browser-noscript {
+  font-weight: bold;
+}
+
+.video-upload-browser-delete {
+  margin-top: 5px;
+  margin-top: 30px !important;
+}
+
+/* Line up the message next to the throbber */
+.video-upload-dialog .upload-validation-message {
+  color: red;
+  line-height:150%;
+  font-size: 0.85em;
+}
+
+.video-upload-dialog {
+  padding-top: 0.5em !important;
+}
+
+/* The throbber we place inside the "Upload" button */
+.video-upload-throbber {
+  margin: 0 5px 0 0 !important;
+}
\ No newline at end of file
diff -upN video_upload\video_upload_browser.js video_upload_browser\video_upload_browser.js
--- video_upload\video_upload_browser.js	Thu Jan 01 01:00:00 1970
+++ video_upload_browser\video_upload_browser.js	Mon May 17 02:32:36 2010
@@ -0,0 +1,203 @@
+// $Id: video_upload_browser.js,v 1.5.6.6 2010/05/16 12:44:03 bojanz Exp $
+/**
+ * JS functionality for the Video Upload Browser method.
+ */
+
+(function ($) {
+
+/**
+ * Implementation of the "Remove" button.
+ */
+Drupal.behaviors.videoUploadAttachDelete = {
+  attach: function(context) {
+    $('.video-upload-browser-delete', context).click(function() {
+      var elementId = this.id;
+      elementId = elementId.replace('-video-browser-delete', '');
+      
+      // Remove the video thumb and status text, reset the hidden fields.
+      $('#' + elementId + '-browser-item').remove();
+      $('#' + elementId + '-video-status').attr('value', 'upload-pending');
+      $('#' + elementId + '-video-id').attr('value', '');
+      
+      var elementWrapper = $('#' + elementId + '-wrapper');
+      var buttonValue = Drupal.t('Launch the Uploader');
+      var uploadButton = '<input type="submit" class="form-submit video-upload-browser-upload" value="' + buttonValue + '" id="' + elementId + '-video-browser-upload" name="op">';
+      
+      if ($('label', elementWrapper).length > 0) { // case when number of values in field is 1
+        $('label', elementWrapper).after(uploadButton);
+      } else { // case when number of values is more than 1
+        elementWrapper.prepend(uploadButton);
+      }
+      
+      // Reattach the JS callback
+      Drupal.behaviors.videoUploadAttachUploaderButton(elementWrapper);
+      
+      return false;
+    });
+  }
+}
+
+/**
+ * Implementation of the "Launch the Uploader" button
+ *  (unhides the button on page load and launches the upload dialog when clicked)
+ */
+Drupal.behaviors.videoUploadAttachUploaderButton = {
+  attach: function(context) {
+    $('.video-upload-browser-upload', context).show();
+    
+    $('.video-upload-browser-upload', context).click(function() {
+      var elementId = this.id;
+      elementId = elementId.replace('-video-browser-upload', '');
+      var dialogId = 'dialog-' + elementId;
+      
+      Drupal.videoUpload.fields.push(elementId);
+      
+      // insert the dialog div with the Loading... text into the DOM
+      $('body').prepend('<div id="' + dialogId + '" class="video-upload-dialog"><br />' + Drupal.t('Loading...') + '</div>');
+      
+      // fetch the upload form from the server, attach the handlers, inject into the dialog
+      $('#' + dialogId).load(Drupal.settings.basePath + 'video-upload/dialog/' + elementId, function(content) {
+        $(this).html(content);
+
+        // Initialize JQuery Form
+        Drupal.videoUpload.attachDialogBehaviour(this);
+        
+        // Show the Upload button.
+        var buttonContext = $(this).parent().parent()[0];
+        $('.ui-dialog-buttonpane', buttonContext).show();
+      });
+      
+      // everything is ready, launch the dialog.
+      Drupal.videoUpload.initializeDialog(dialogId);
+        
+      return false;
+    });
+  }
+}
+
+Drupal.videoUpload = function() {};
+
+/**
+ * A stack containing the field ids of widgets from which we launched dialogs.
+ * This is needed because when an upload finishes, we don't actually know
+ * which dialog finished (and we don't care), we just kill one, and fill one
+ * empty space in the node add/edit form.
+ *
+ * This is done this way because we can't pass any params to the YouTube $nextUrl
+ * and have them provided there (as a POST or GET param), which sucks.
+ */
+Drupal.videoUpload.fields = new Array();
+
+/**
+ * Initialize the JQuery UI Dialog.
+ */
+Drupal.videoUpload.initializeDialog = function(dialogId) {
+  var buttons = {};
+  var uploadLabel = Drupal.t("Upload");
+  
+  buttons[uploadLabel] = function() {
+    $('form', this).submit();
+  };
+  
+  $('#' + dialogId).dialog({
+    title: Drupal.t('Upload a file to YouTube'),
+    resizable: true,
+    maximize: false,
+    draggable: true,
+    position: 'center',
+    height: 195,
+    width: 400,
+    close: function(event, ui) {
+      var dialogId = $(this).attr('id');
+      var elementId = dialogId.replace('dialog-', '');
+      var elementPos = jQuery.inArray(elementId, Drupal.videoUpload.fields);
+      
+      Drupal.videoUpload.fields.splice(elementPos, 1);
+    },
+    buttons: buttons
+  });
+  
+  var buttonContext = $('#' + dialogId).parent().parent()[0];
+  
+  // Hide the Upload button (shown when the upload form loads)
+  $('.ui-dialog-buttonpane', buttonContext).css('display', 'none');
+}
+
+
+/**
+ * Initialize JQuery Form and attach it to the form in the dialog.
+ */
+Drupal.videoUpload.attachDialogBehaviour = function(context) {  
+  var elementId = $('#edit-element-id', context).attr('value');
+
+  var options = {
+    context: context,
+    elementId: elementId,
+    beforeSubmit:  Drupal.videoUpload.beforeSubmit, 
+    success:       Drupal.videoUpload.completeUpload
+  };
+  
+  $('form', context).ajaxForm(options);
+}
+
+// JQuery Form presubmit handler
+Drupal.videoUpload.beforeSubmit = function(formData, jqForm, options) {    
+  // Remove previous error message, if any
+  $('.upload-validation-message', options.context).remove();
+  
+  if ($('input[type=file]', options.context).attr('value') == "") {
+    var errorMessage = Drupal.t('No file selected.');
+    $('.form-item-files-upload', options.context).append('<div class="upload-validation-message">' + errorMessage + '</div>');
+    
+    return false;
+  }
+  
+  var buttonContext = $('#dialog-' + options.elementId).parent().parent()[0];
+  
+  var button = Drupal.t('Uploading...');
+  
+  /*
+    For browsers that are not IE6/7 we insert a throbber.
+    The throbber looks like crap on IE6/IE7, so we have to can't use it.
+  */
+  //if(!$.browser.msie || $.browser.version > 7) {
+  //  button = '<div class="ahah-progress ahah-progress-throbber">' +
+  //             '<div class="throbber video-upload-throbber">&nbsp;</div>' +
+  //            '</div>' + button;
+  //}
+
+  $('button', buttonContext).html(button);
+  
+  return true;
+}
+
+/**
+ * JQuery Form postsubmit handler.
+ * Parses the response, closes the dialog, updates the widget on the
+ * node add/edit page.
+ */
+Drupal.videoUpload.completeUpload = function(responseText) {
+  var response = Drupal.parseJson(responseText);
+  var elementId = Drupal.videoUpload.fields.shift();
+  
+  response.field = response.field.replace(/\$element\_id/g, elementId);
+  
+  $('#dialog-' + elementId).dialog('destroy');
+  
+  // remove the upload button, update the hidden fields
+  $('#' + elementId + '-video-browser-upload').remove();
+  $('#' + elementId + '-video-status').attr('value', 'unknown');
+  $('#' + elementId + '-video-id').attr('value', response.id);
+  
+  if ($('#' + elementId + '-wrapper label', elementWrapper).length > 0) { // case when number of values in field is 1
+    $('#' + elementId + '-wrapper label').after(response.field);
+  } else { // case when number of values is more than 1
+    $('#' + elementId + '-wrapper').prepend(response.field);
+  }
+  
+  // reattach the js handler for the Remove button
+  var elementWrapper = $('#' + elementId + '-wrapper')[0];
+  Drupal.behaviors.videoUploadAttachDelete(elementWrapper);
+}
+
+})(jQuery);
\ No newline at end of file
Common subdirectories: video_upload\views and video_upload_browser\views
