12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196 |
- <?php
- /**
- * @file
- * Common Translation managment UI.
- */
- /**
- * Implements hook_entity_info().
- */
- function tmgmt_ui_entity_info() {
- $info['tmgmt_translator'] = array(
- 'admin ui' => array(
- 'controller class' => 'TMGMTTranslatorUIController',
- 'path' => 'admin/config/regional/tmgmt_translator',
- ),
- );
- $info['tmgmt_job'] = array(
- 'admin ui' => array(
- 'controller class' => 'TMGMTJobUIController',
- 'path' => 'admin/tmgmt/jobs',
- ),
- );
- $info['tmgmt_job_item'] = array(
- 'admin ui' => array(
- 'controller class' => 'TMGMTJobItemUIController',
- 'path' => 'admin/tmgmt/items',
- ),
- );
- foreach ($info as $key => $item) {
- // Entity API defaults to the path that implements the entity type, but
- // since this happens in the TMGMT core module, we need to manually
- // define the path here.
- $info[$key]['admin ui']['file path'] = drupal_get_path('module', 'tmgmt_ui');
- $info[$key]['admin ui']['file'] = 'includes/tmgmt_ui.pages.inc';
- }
- return $info;
- }
- /**
- * Implements hook_menu().
- */
- function tmgmt_ui_menu() {
- $items['admin/config/regional/tmgmt_settings'] = array(
- 'title' => 'Translation Management settings',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('tmgmt_ui_settings_form'),
- 'access arguments' => array('administer tmgmt'),
- 'file' => 'includes/tmgmt_ui.pages.inc',
- 'weight' => 10,
- );
- $items['admin/tmgmt/cart'] = array(
- 'title' => 'Cart',
- 'title callback' => 'tmgmt_ui_cart_title',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('tmgmt_ui_cart_content'),
- 'access arguments' => array('create translation jobs'),
- 'file' => 'includes/tmgmt_ui.pages.inc',
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 20,
- );
- // Some source plugins might provide menu items.
- foreach (tmgmt_source_ui_controller() as $controller) {
- $items += $controller->hook_menu();
- }
- return $items;
- }
- /**
- * Cart page title callback.
- *
- * @return string
- */
- function tmgmt_ui_cart_title() {
- return t('Cart (@count)', array('@count' => tmgmt_ui_cart_get()->count()));
- }
- /**
- * Implements hook_module_implements_alter().
- */
- function tmgmt_ui_module_implements_alter(&$implementations, $hook) {
- if ($hook == 'menu_alter') {
- // Move tmgmt_ui_menu_alter() to the end to be able to see views-defined
- // source overviews.
- $group = $implementations['tmgmt_ui'];
- unset($implementations['tmgmt_ui']);
- $implementations['tmgmt_ui'] = $group;
- }
- }
- /**
- * Implements hook_menu_alter().
- */
- function tmgmt_ui_menu_alter(&$items) {
- $weight = NULL;
- $default_path = NULL;
- // Look for the sources overview local task with the lowest weight.
- foreach ($items as $path => $item) {
- $item += array('weight' => 0);
- if (strpos($path, 'admin/tmgmt/sources') !== FALSE) {
- if ($weight === NULL || $weight > $item['weight']) {
- $weight = $item['weight'];
- $default_path = $path;
- }
- }
- }
- // If we have found a default path, define a parent menu item based on it's
- // definitions and change the type to a default local task.
- if ($default_path) {
- $items['admin/tmgmt/sources'] = array(
- 'title' => 'Sources',
- 'description' => 'Source overview',
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 10,
- ) + $items[$default_path];
- $items[$default_path]['type'] = MENU_DEFAULT_LOCAL_TASK;
- }
- }
- /**
- * Implements hook_theme().
- */
- function tmgmt_ui_theme() {
- return array(
- 'tmgmt_ui_translator_overview_item' => array(
- // We also have the entity_type here because we are still populating the
- // defaults via the entity api so we just need to add the description.
- 'variables' => array('label' => NULL, 'entity_type' => NULL, 'url' => FALSE, 'name' => FALSE, 'description' => FALSE),
- 'file' => 'includes/tmgmt_ui.theme.inc',
- ),
- 'tmgmt_ui_translator_overview_form' => array(
- 'render element' => 'form',
- 'file' => 'includes/tmgmt_ui.theme.inc',
- ),
- 'tmgmt_ui_translator_review_form' => array(
- 'render element' => 'element',
- 'file' => 'includes/tmgmt_ui.theme.inc',
- ),
- 'tmgmt_ui_translator_review_form_element' => array(
- 'render element' => 'element',
- 'file' => 'includes/tmgmt_ui.theme.inc',
- ),
- 'tmgmt_ui_translator_review_form_element_status' => array(
- 'render element' => 'status',
- 'file' => 'includes/tmgmt_ui.theme.inc',
- ),
- 'tmgmt_ui_translation_language_status_single' => array(
- 'file' => 'includes/tmgmt_ui.theme.inc',
- 'variables' => array('translation_status' => NULL, 'job_item' => NULL),
- ),
- );
- }
- /**
- * Implements hook_forms().
- */
- function tmgmt_ui_forms() {
- $forms = array();
- foreach (tmgmt_source_plugin_info() as $plugin => $info) {
- $forms['tmgmt_ui_' . $plugin . '_translation_review_form'] = array(
- 'callback' => 'tmgmt_ui_translation_review_form',
- 'wrapper_callback' => 'tmgmt_ui_translation_review_form_defaults',
- );
- }
- // Some source plugins might provide forms.
- foreach (tmgmt_source_ui_controller() as $controller) {
- $forms += $controller->hook_forms();
- }
- return $forms;
- }
- /**
- * Implements hook_system_info_alter().
- */
- function tmgmt_ui_system_info_alter(&$info, $file, $type) {
- if ($file->name == 'tmgmt') {
- $info['configure'] = 'admin/config/regional/tmgmt_settings';
- }
- }
- /**
- * Implements hook_views_api().
- */
- function tmgmt_ui_views_api() {
- return array('api' => 3.0);
- }
- /**
- * Implements hook_views_default_views().
- */
- function tmgmt_ui_views_default_views() {
- $views = _tmgmt_load_exports('tmgmt_ui', 'views', 'view.inc', 'view');
- // Some source controllers might provide custom views.
- foreach (tmgmt_source_ui_controller() as $controller) {
- $views += $controller->hook_views_default_views();
- }
- return $views;
- }
- /**
- * Embed a view but don't render it if it's empty.
- *
- * @param string $view
- * The machine-readable name of the view.
- * @param string $display_id
- * The display id for the view.
- * @param array $args
- * The arguments that should be passed to the view.
- *
- * @return
- * The rendered view or an empty string if the view doesn't exist if it was
- * empty.
- */
- function tmgmt_ui_embed_view($view, $display_id = NULL, array $args = array()) {
- $view = views_get_view($view);
- if (!empty($view)) {
- $view->init_display();
- $output = $view->preview($display_id, $args);
- if (!empty($view->result)) {
- return $output;
- }
- }
- return '';
- }
- /**
- * Form callback for the source overview form.
- */
- function tmgmt_ui_source_overview_form($form, &$form_state, $plugin, $item_type = NULL) {
- $controller = tmgmt_source_ui_controller($plugin);
- $form_state['plugin'] = $plugin;
- $form_state['item_type'] = $item_type;
- return $controller->overviewForm($form, $form_state, $item_type);
- }
- /**
- * Form callback for the source overview form.
- */
- function tmgmt_ui_source_overview_form_defaults($form, &$form_state, $plugin, $item_type = NULL) {
- $controller = tmgmt_source_plugin_controller($plugin);
- $info = tmgmt_source_plugin_info($plugin);
- // Set a generic title that includes the source plugin and item type label.
- drupal_set_title(t('@type overview (@plugin)', array('@type' => $controller->getItemTypeLabel($item_type), '@plugin' => $info['label'])), PASS_THROUGH);
- $form['actions'] = array(
- '#type' => 'fieldset',
- '#title' => t('Operations'),
- '#collapsible' => TRUE,
- '#collapsed' => FALSE,
- '#weight' => -10,
- '#attributes' => array('class' => array('tmgmt-source-operations-wrapper'))
- );
- tmgmt_ui_add_cart_form($form['actions'], $form_state, $plugin, $item_type);
- $form['actions']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Request translation'),
- );
- return $form;
- }
- /**
- * Validation callback for the source overview form.
- */
- function tmgmt_ui_source_overview_form_validate($form, &$form_state) {
- // Copy the form state so we are not removing important information from it
- // when sending it through form_state_values_clean().
- $cleaned = $form_state;
- form_state_values_clean($cleaned);
- if (empty($cleaned['values'])) {
- form_set_error('items', t("You didn't select any source objects"));
- }
- list($plugin, $item_type) = $form_state['build_info']['args'];
- // Execute the validation method on the source plugin controller.
- $controller = tmgmt_source_ui_controller($plugin);
- $controller->overviewFormValidate($form, $form_state, $item_type);
- }
- /**
- * Submit callback for the source overview form.
- */
- function tmgmt_ui_source_overview_form_submit($form, &$form_state) {
- list($plugin, $item_type) = $form_state['build_info']['args'];
- // Execute the submit method on the source plugin controller.
- $controller = tmgmt_source_ui_controller($plugin);
- $controller->overviewFormSubmit($form, $form_state, $item_type);
- }
- /**
- * Gets the tmgmt cart singleton object.
- *
- * @return TMGMTJobItemUICart
- * The cart object.
- */
- function tmgmt_ui_cart_get() {
- return TMGMTJobItemUICart::getInstance();
- }
- /**
- * @addtogroup tmgmt_ui_cart
- * @{
- */
- /**
- * Adds add to cart form elements.
- *
- * There are two use cases for this function:
- *
- * 1) Add the "Add to cart" submit action to the source overview form. In this
- * case the $item_id should not be provided and only the action button will be
- * displayed. The form is expected to submit job items ids as items[] which is
- * being validated via tmgmt_ui_source_add_to_cart_validate().
- *
- * 2) Add the "Add to cart" submit action to the translate tab. For this case
- * the $item_id is required and with the add to cart button also the cart
- * information is displayed. In this case there is no validation as the caller
- * needs to provide valid $item_id value.
- *
- * The "Add to cart" action submits the form by calling
- * tmgmt_ui_source_add_to_cart_submit() submit callback which processes either
- * one job item or multiple.
- *
- * @param array $form
- * Form to which to add the add to cart form elements.
- * @param array $form_state
- * The current form state object.
- * @param string $plugin
- * Current plugin name.
- * @param string $item_type
- * Type of the source item.
- * @param mixed $item_id
- * (Optional) It is required in case a single source is being added into the
- * cart.
- */
- function tmgmt_ui_add_cart_form(&$form, &$form_state, $plugin, $item_type, $item_id = NULL) {
- $form_state['tmgmt_cart'] = array(
- 'plugin' => $plugin,
- 'item_type' => $item_type,
- 'item_id' => $item_id,
- );
- $form['add_to_cart'] = array(
- '#type' => 'submit',
- '#value' => t('Add to cart'),
- '#submit' => array('tmgmt_ui_source_add_to_cart_submit'),
- '#attributes' => array('title' => t('Add marked items to the cart for later processing')),
- );
- if (empty($item_id)) {
- $form['add_to_cart']['#validate'] = array('tmgmt_ui_cart_source_overview_validate');
- }
- else {
- //
- $form['add_to_cart']['#limit_validation_errors'] = array();
- // Compose the cart info message for the translate tab.
- $count = tmgmt_ui_cart_get()->count();
- if (tmgmt_ui_cart_get()->isSourceItemAdded($plugin, $item_type, $item_id)) {
- $form['add_to_cart']['#disabled'] = TRUE;
- $message = format_plural($count, 'There is @count item in the <a href="@url">translation cart</a> including the current item.',
- 'There are @count items in the <a href="@url">translation cart</a> including the current item.', array('@url' => url('admin/tmgmt/cart')));
- }
- else {
- $message = format_plural($count, 'There is @count item in the <a href="@url">translation cart</a>.',
- 'There are @count items in the <a href="@url">translation cart</a>.', array('@url' => url('admin/tmgmt/cart')));
- }
- $form['add_to_cart']['#suffix'] = '<span class="tmgmt-ui-cart-status-message">' . $message . '</span>';
- }
- }
- /**
- * Submit handler to add items into the cart.
- *
- * Based on the submitted data it will create job items and add them into the
- * cart. Use it in combination with tmgmt_ui_add_cart_form() as that function
- * sets all the necessary values needed to crate a job an add it into the cart.
- *
- * @see tmgmt_ui_add_cart_form()
- */
- function tmgmt_ui_source_add_to_cart_submit($form, &$form_state) {
- $cart_info = $form_state['tmgmt_cart'];
- if (!empty($cart_info['plugin']) && !empty($cart_info['item_type']) && !empty($form_state['values']['items'])) {
- $source_items = array_filter($form_state['values']['items']);
- $item_type = $cart_info['item_type'];
- $plugin = $cart_info['plugin'];
- }
- elseif (!empty($cart_info['plugin']) && !empty($cart_info['item_type']) && !empty($cart_info['item_id'])) {
- $source_items = array($cart_info['item_id']);
- $item_type = $cart_info['item_type'];
- $plugin = $cart_info['plugin'];
- }
- else {
- drupal_set_message(t('Unable to add the content into the cart.'), 'error');
- return;
- }
- $i = 0;
- foreach ($source_items as $source_id) {
- if (tmgmt_ui_cart_get()->addJobItem($plugin, $item_type, $source_id)) {
- $i++;
- }
- }
- drupal_set_message(format_plural($i, '@count content source was added into the <a href="@url">cart</a>.',
- '@count content sources were added into the <a href="@url">cart</a>.', array('@url' => url('admin/tmgmt/cart'))));
- }
- /**
- * Cart form validation callback for the source overview.
- */
- function tmgmt_ui_cart_source_overview_validate($form, &$form_state) {
- $items = array_filter($form_state['values']['items']);
- if (empty($items)) {
- form_set_error('items', t('No job items were selected.'));
- }
- }
- /**
- * @} End of "addtogroup tmgmt_ui_cart".
- */
- /**
- * Attempts to check out a number of jobs. Performs a number of checks on each
- * job and also allows to alter the behavior through hooks.
- *
- * @param $jobs
- * The jobs to be checked out.
- *
- * @return
- * Array of redirect url's if there are any jobs that need manual checkout.
- *
- * @ingroup tmgmt_job
- *
- * @see tmgmt_ui_redirect_queue()
- * @see tmgmt_ui_job_checkout_and_redirect()
- */
- function tmgmt_ui_job_checkout_multiple(array $jobs) {
- $redirects = array();
- // Allow other modules to jump in and eg. auto-checkout with rules or use a
- // customized checkout form.
- drupal_alter('tmgmt_ui_job_checkout_before', $redirects, $jobs);
- $denied = 0;
- foreach ($jobs as $job) {
- if (!$job->isUnprocessed()) {
- // Job is already checked out, just ignore that one. This could happen
- // if jobs have already been submitted in the before hook.
- continue;
- }
- if (!variable_get('tmgmt_quick_checkout', TRUE) || tmgmt_ui_job_needs_checkout_form($job)) {
- if (!entity_access('submit', 'tmgmt_job', $job)) {
- // Ignore jobs if the user is not allowed to submit, ignore.
- $denied++;
- // Make sure that the job is saved.
- $job->save();
- continue;
- }
- $uri = $job->uri();
- $redirects[] = $uri['path'];
- }
- else {
- // @todo this is dangerous because we don't catch request fails at all.
- // Normally I would expect this to catch all failed requests and
- // afterwards send the user through a multistep form which contains the
- // failed elements.
- // No manual checkout required. Request translations now.
- tmgmt_ui_job_request_translation($job);
- }
- }
- // Allow other modules to jump in and eg. auto-checkout with rules or use a
- // customized checkout form.
- drupal_alter('tmgmt_ui_job_checkout_after', $redirects, $jobs);
- // Display message for created jobs that can not be checked out.
- if ($denied) {
- drupal_set_message(format_plural($denied, 'One job has been created.', '@count jobs have been created.'));
- }
- return $redirects;
- }
- /**
- * Check if a job needs a checkout form. The current checks include if there is
- * more than one translator available, if he has settings and if the job has a
- * fixed target language.
- *
- * @param TMGMTJob $job
- * The job item
- *
- * @return
- * TRUE if the job needs a checkout form.
- */
- function tmgmt_ui_job_needs_checkout_form(TMGMTJob $job) {
- // If the job has no target language (or source language, even though this
- // should never be the case in our use case), checkout is mandatory.
- if (empty($job->target_language) || empty($job->source_language)) {
- return TRUE;
- }
- // If no translator is pre-selected, try to pick one automatically.
- if (empty($job->translator)) {
- // If there is more than a single translator available or if there are no
- // translators available at all checkout is mandatory.
- $translators = tmgmt_translator_load_available($job);
- if (empty($translators) || count($translators) > 1) {
- return TRUE;
- }
- $translator = reset($translators);
- $job->translator = $translator->name;
- }
- // If that translator has settings, the checkout is mandatory.
- if ($job->getTranslator()->hasCheckoutSettings($job)) {
- return TRUE;
- }
- return FALSE;
- }
- /**
- * Requests translations for a job and prints messages which have happened since
- * then.
- *
- * @param TMGMTJob $job
- * The job object for which translations should be requested.
- *
- * @return
- * TRUE if it worked, FALSE if there were any errors of the type error which
- * means that something did go wrong.
- */
- function tmgmt_ui_job_request_translation(TMGMTJob $job) {
- // Process the translation request.
- $job->requestTranslation();
- return tmgmt_ui_write_request_messages($job);
- }
- /**
- * Print all messages that occurred since our request to the screen.
- *
- * @param $job
- * The translation job for which the message should be written.
- *
- * @return
- * FALSE if there are message with severity error, TRUE otherwise.
- */
- function tmgmt_ui_write_request_messages(TMGMTJob $job) {
- $errors = FALSE;
- foreach ($job->getMessagesSince() as $message) {
- // Ignore debug messages.
- if ($message->type == 'debug') {
- continue;
- }
- if ($message->type == 'error') {
- $errors = TRUE;
- }
- if ($text = $message->getMessage()) {
- drupal_set_message(filter_xss($text), $message->type);
- }
- }
- return !$errors;
- }
- /**
- * Form wrapper callback for the job item review form.
- *
- * @see tmgmt_ui_forms()
- */
- function tmgmt_ui_translation_review_form_defaults($form, &$form_state, TMGMTJobItem $item) {
- // We store the item in the root of the form state so we can easily access it
- // in all the form functions.
- $form_state['item'] = $item;
- $wrapper = entity_metadata_wrapper('tmgmt_job_item', $item);
- $form['info'] = array(
- '#type' => 'container',
- '#attributes' => array('class' => array('tmgmt-ui-job-info', 'clearfix')),
- '#weight' => 0,
- );
- $uri = $item->getSourceUri();
- $form['info']['source'] = array(
- '#type' => 'item',
- '#title' => t('Source'),
- '#markup' => !empty($uri) ? l($item->getSourceLabel(), $uri['path'], $uri['options']) : $item->getSourceLabel(),
- '#prefix' => '<div class="tmgmt-ui-source tmgmt-ui-info-item">',
- '#suffix' => '</div>',
- );
- $form['info']['sourcetype'] = array(
- '#type' => 'item',
- '#title' => t('Source type'),
- '#markup' => $item->getSourceType(),
- '#prefix' => '<div class="tmgmt-ui-source-type tmgmt-ui-info-item">',
- '#suffix' => '</div>',
- );
- $form['info']['changed'] = array(
- '#type' => 'item',
- '#title' => t('Last change'),
- '#markup' => format_date($wrapper->changed->value()),
- '#prefix' => '<div class="tmgmt-ui-changed tmgmt-ui-info-item">',
- '#suffix' => '</div>',
- );
- $form['info']['state'] = array(
- '#type' => 'item',
- '#title' => t('State'),
- '#markup' => $wrapper->state->label(),
- '#prefix' => '<div class="tmgmt-ui-item-state tmgmt-ui-info-item">',
- '#suffix' => '</div>',
- );
- $job = $item->getJob();
- $uri = $job->uri();
- $form['info']['job'] = array(
- '#type' => 'item',
- '#title' => t('Job'),
- '#markup' => l($job->label(), $uri['path']),
- '#prefix' => '<div class="tmgmt-ui-job tmgmt-ui-info-item">',
- '#suffix' => '</div>',
- );
- // Display selected translator for already submitted jobs.
- if (!$item->getJob()->isSubmittable()) {
- $translators = tmgmt_translator_labels();
- $form['info']['translator'] = array(
- '#type' => 'item',
- '#title' => t('Translator'),
- '#markup' => isset($translators[$item->getJob()->translator]) ? check_plain($translators[$item->getJob()->translator]) : t('Missing translator'),
- '#prefix' => '<div class="tmgmt-ui-translator tmgmt-ui-info-item">',
- '#suffix' => '</div>',
- );
- }
- // Actually build the review form elements...
- $form['review'] = array(
- '#type' => 'container',
- );
- // Build the review form.
- $data = $item->getData();
- // Need to keep the first hierarchy. So flatten must take place inside
- // of the foreach loop.
- $zebra = 'even';
- foreach (element_children($data) as $key) {
- $form['review'][$key] = _tmgmt_ui_review_form_element($form_state, tmgmt_flatten_data($data[$key], $key), $item, $zebra, $key);
- }
- if ($output = tmgmt_ui_embed_view('tmgmt_ui_job_item_messages', 'block', array($item->tjiid))) {
- $form['messages'] = array(
- '#type' => 'fieldset',
- '#title' => t('Messages'),
- '#collapsible' => TRUE,
- '#collapsed' => TRUE,
- '#weight' => 50,
- );
- $form['messages']['view'] = array(
- '#type' => 'item',
- '#markup' => $output,
- );
- }
- // Add the form actions as well.
- $form['actions']['#type'] = 'actions';
- $form['actions']['accept'] = array(
- '#type' => 'submit',
- '#value' => t('Save as completed'),
- '#access' => $item->isNeedsReview(),
- );
- $form['actions']['save'] = array(
- '#type' => 'submit',
- '#value' => t('Save'),
- '#access' => !$item->isAccepted() && !$item->isAborted(),
- );
- $uri = $item->getJob()->uri();
- $url = isset($_GET['destination']) ? $_GET['destination'] : $uri['path'];
- $form['actions']['cancel'] = array(
- '#type' => 'link',
- '#title' => t('Cancel'),
- '#href' => $url,
- );
- $form['#attached']['css'][] = drupal_get_path('module', 'tmgmt_ui') . '/css/tmgmt_ui.admin.css';
- // The reject functionality has to be implement by the translator plugin as
- // that process is completely unique and custom for each translation service.
- return $form;
- }
- /**
- * Helper function to output ajaxid.
- *
- * @param string $parent_key
- * Parent element key.
- *
- * @return string
- * The ajax id.
- */
- function tmgmt_ui_review_form_element_ajaxid($parent_key) {
- return 'tmgmt-ui-element-' . drupal_clean_css_identifier($parent_key) . '-wrapper';
- }
- /**
- * Build form elements for the review form using flatened data items.
- *
- * @todo Mention in the api documentation that the char '|' is not allowed in
- * field names.
- *
- * @param array $form_state
- * Drupal form form_state object.
- * @param $data
- * Flatened array of translation data items.
- * @param $job_item
- * The job item related to this data.
- * @param $zebra
- * String containing either odd or even. This is used to style the each
- * translation item with alternating colors.
- * @param $parent_key
- * The key for $data.
- */
- function _tmgmt_ui_review_form_element(&$form_state, $data, TMGMTJobItem $job_item, &$zebra, $parent_key) {
- $flip = array(
- 'even' => 'odd',
- 'odd' => 'even',
- );
- $form = array(
- '#theme' => 'tmgmt_ui_translator_review_form',
- '#ajaxid' => tmgmt_ui_review_form_element_ajaxid($parent_key),
- );
- foreach (element_children($data) as $key) {
- // The char sequence '][' confuses the form API so we need to replace it.
- $target_key = str_replace('][', '|', $key);
- if (isset($data[$key]['#text']) && _tmgmt_filter_data($data[$key])) {
- $zebra = $flip[$zebra];
- $form[$target_key] = array(
- '#tree' => TRUE,
- '#theme' => 'tmgmt_ui_translator_review_form_element',
- '#parent_label' => $data[$key]['#parent_label'],
- '#zebra' => $zebra,
- );
- $form[$target_key]['status'] = array(
- '#theme' => 'tmgmt_ui_translator_review_form_element_status',
- '#value' => $job_item->isAccepted() ? TMGMT_DATA_ITEM_STATE_ACCEPTED : $data[$key]['#status'],
- );
- $form[$target_key]['actions'] = array(
- '#type' => 'container',
- );
- // Display data item actions unless the job item is accepted or aborted.
- if (!$job_item->isAccepted() && !$job_item->isAborted()) {
- if ($data[$key]['#status'] != TMGMT_DATA_ITEM_STATE_REVIEWED) {
- $form[$target_key]['actions']['reviewed'] = array(
- '#type' => 'submit',
- // Unicode character ✓ CHECK MARK
- '#value' => '✓',
- '#attributes' => array('title' => t('Reviewed')),
- '#name' => 'reviewed-' . $target_key,
- '#submit' => array('tmgmt_ui_translation_review_form_update_state', 'tmgmt_ui_translation_review_form_submit'),
- '#ajax' => array(
- 'callback' => 'tmgmt_ui_translation_review_form_ajax',
- 'wrapper' => $form['#ajaxid'],
- ),
- );
- }
- else {
- $form[$target_key]['actions']['unreviewed'] = array(
- '#type' => 'submit',
- // Unicode character ✓ CHECK MARK
- '#value' => '✓',
- '#attributes' => array('title' => t('Not reviewed'), 'class' => array('unreviewed')),
- '#name' => 'unreviewed-' . $target_key,
- '#submit' => array('tmgmt_ui_translation_review_form_update_state', 'tmgmt_ui_translation_review_form_submit'),
- '#ajax' => array(
- 'callback' => 'tmgmt_ui_translation_review_form_ajax',
- 'wrapper' => $form['#ajaxid'],
- ),
- );
- }
- if ($job_item->getTranslatorController() instanceof TMGMTTranslatorRejectDataItem && $data[$key]['#status'] != TMGMT_DATA_ITEM_STATE_PENDING) {
- $form[$target_key]['actions']['reject'] = array(
- '#type' => 'submit',
- // Unicode character ✗ BALLOT X
- '#value' => '✗',
- '#attributes' => array('title' => t('Reject')),
- '#name' => 'reject-' . $target_key,
- '#submit' => array('tmgmt_ui_translation_review_form_update_state'),
- );
- }
- if (!empty($data[$key]['#translation']['#text_revisions'])) {
- $form[$target_key]['actions']['revert'] = array(
- '#type' => 'submit',
- // Unicode character U+21B6 ANTICLOCKWISE TOP SEMICIRCLE ARROW
- '#value' => '↶',
- '#attributes' => array('title' => t('Revert to previous revision')),
- '#name' => 'revert-' . $target_key,
- '#data_item_key' => $key,
- '#submit' => array('tmgmt_ui_translation_review_form_revert'),
- '#ajax' => array(
- 'callback' => 'tmgmt_ui_translation_review_form_ajax',
- 'wrapper' => $form['#ajaxid'],
- ),
- );
- }
- }
- if (!empty($data[$key]['#translation']['#text_revisions'])) {
- $revisions = array();
- foreach ($data[$key]['#translation']['#text_revisions'] as $revision) {
- $revisions[] = t('Origin: %origin, Created: %created<br />%text', array(
- '%origin' => $revision['#origin'],
- '%created' => format_date($revision['#timestamp']),
- '%text' => filter_xss($revision['#text']),
- ));
- }
- $form[$target_key]['below']['revisions_wrapper'] = array(
- '#type' => 'fieldset',
- '#title' => t('Translation revisions'),
- '#collapsed' => TRUE,
- '#collapsible' => TRUE,
- );
- $form[$target_key]['below']['revisions_wrapper']['revisions'] = array(
- '#theme' => 'item_list',
- '#items' => $revisions,
- );
- }
- $form[$target_key]['translation'] = array(
- '#type' => 'textarea',
- '#default_value' => isset($data[$key]['#translation']['#text']) ? $data[$key]['#translation']['#text'] : NULL,
- '#title' => t('Translation'),
- '#disabled' => $job_item->isAccepted(),
- );
- $form[$target_key]['source'] = array(
- '#type' => 'textarea',
- '#default_value' => $data[$key]['#text'],
- '#title' => t('Source'),
- '#disabled' => TRUE,
- '#allow_focus' => TRUE,
- );
- // Give the translator ui controller a chance to affect the data item element.
- if ($translator = $job_item->getTranslator()) {
- $form[$target_key] = tmgmt_translator_ui_controller($translator->plugin)
- ->reviewDataItemElement($form[$target_key], $form_state, $key, $parent_key, $data[$key], $job_item);
- }
- // Give the source ui controller a chance to affect the data item element.
- $form[$target_key] = tmgmt_source_ui_controller($job_item->plugin)
- ->reviewDataItemElement($form[$target_key], $form_state, $key, $parent_key, $data[$key], $job_item);
- }
- }
- return $form;
- }
- /**
- * Review form revert action callback.
- */
- function tmgmt_ui_translation_review_form_revert($form, &$form_state) {
- /** @var TMGMTJobItem $item */
- $item = $form_state['item'];
- $key = tmgmt_ensure_keys_array($form_state['triggering_element']['#data_item_key']);
- if ($item->dataItemRevert($key)) {
- // Update the form_state input values so that the new default vale will be
- // shown.
- $form_key = str_replace('][', '|', $form_state['triggering_element']['#data_item_key']);
- unset($form_state['input'][$form_key]['translation']);
- $item->save();
- }
- else {
- drupal_set_message(t('No past revision found, translation was not reverted.'), 'warning');
- }
- $form_state['rebuild'] = TRUE;
- }
- /**
- * Form callback for the job item review form.
- *
- * @see tmgmt_ui_forms()
- */
- function tmgmt_ui_translation_review_form($form, &$form_state, TMGMTJobItem $item) {
- // Give the source ui controller a chance to affect the review form.
- $source = tmgmt_source_ui_controller($item->plugin);
- $form = $source->reviewForm($form, $form_state, $item);
- // Give the translator ui controller a chance to affect the review form.
- if ($item->getTranslator()) {
- $translator = tmgmt_translator_ui_controller($item->getTranslator()->plugin);
- $form = $translator->reviewForm($form, $form_state, $item);
- }
- return $form;
- }
- /**
- * Validation callback for the job item review form.
- */
- function tmgmt_ui_translation_review_form_validate($form, &$form_state) {
- $item = $form_state['item'];
- // First invoke the validation method on the source controller.
- $source = tmgmt_source_ui_controller($item->plugin);
- $source->reviewFormValidate($form, $form_state, $item);
- // Invoke the validation method on the translator controller (if available).
- if($item->getTranslator()){
- $translator = tmgmt_translator_ui_controller($item->getTranslator()->plugin);
- $translator->reviewFormValidate($form, $form_state, $item);
- }
- }
- /**
- * Submit callback for the job item review form.
- */
- function tmgmt_ui_translation_review_form_submit($form, &$form_state) {
- /** @var TMGMTJobItem $item */
- $item = $form_state['item'];
- // First invoke the submit method on the source controller.
- $source = tmgmt_source_ui_controller($item->plugin);
- $source->reviewFormSubmit($form, $form_state, $item);
- // Invoke the submit method on the translator controller (if available).
- if($item->getTranslator()){
- $translator = tmgmt_translator_ui_controller($item->getTranslator()->plugin);
- $translator->reviewFormSubmit($form, $form_state, $item);
- }
- // Write changes back to item.
- foreach ($form_state['values'] as $key => $value) {
- if (is_array($value) && isset($value['translation'])) {
- // Update the translation, this will only update the translation in case
- // it has changed.
- $data = array(
- '#text' => $value['translation'],
- '#origin' => 'local',
- );
- $item->addTranslatedData($data, $key);
- }
- }
- // Check if the user clicked on 'Accept', 'Submit' or 'Reject'.
- if (!empty($form['actions']['accept']) && $form_state['triggering_element']['#value'] == $form['actions']['accept']['#value']) {
- $item->acceptTranslation();
- // Check if the item could be saved and accepted successfully and redirect
- // to the job item view if that is the case.
- if ($item->isAccepted()) {
- $uri = $item->uri();
- $form_state['redirect'] = $uri['path'];
- }
- // Print all messages that have been saved while accepting the reviewed
- // translation.
- foreach ($item->getMessagesSince() as $message) {
- // Ignore debug messages.
- if ($message->type == 'debug') {
- continue;
- }
- if ($text = $message->getMessage()) {
- drupal_set_message(filter_xss($text), $message->type);
- }
- }
- }
- $item->save();
- }
- /**
- * Callback for the action at the job item review form.
- */
- function tmgmt_ui_translation_review_form_update_state($form, &$form_state) {
- $matches = array();
- // We should have an #name element
- // and the name should beginn with approve-
- // and the $matches should now kontain an element with with name key.
- preg_match("/^(?P<action>[^-]+)-(?P<key>.+)/i", $form_state['triggering_element']['#name'], $matches);
- $values = $form_state['values'];
- $data = array();
- $job_item = $form_state['item'];
- $controller = $job_item->getTranslatorController();
- $success = TRUE;
- switch ($matches['action']) {
- case 'reviewed':
- $form_state['rebuild'] = TRUE;
- $data['#status'] = TMGMT_DATA_ITEM_STATE_REVIEWED;
- break;
- case 'unreviewed':
- $form_state['rebuild'] = TRUE;
- $data['#status'] = TMGMT_DATA_ITEM_STATE_TRANSLATED;
- break;
- case 'reject':
- if (empty($values['confirm'])) {
- if (isset($_GET['destination'])) {
- $destination = $_GET['destination'];
- unset($_GET['destination']);
- }
- else {
- $destination = '';
- }
- tmgmt_ui_redirect_queue_set(array(current_path()), $destination);
- $form_state['redirect'] = current_path() . '/reject/' . $matches['key'];
- $success = FALSE;
- }
- else {
- $form_state['redirect'] = array(tmgmt_ui_redirect_queue_dequeue(), array( 'query' => array('destination' => tmgmt_ui_redirect_queue_destination())));
- if ($controller instanceof TMGMTTranslatorRejectDataItem) {
- $success = $job_item->getTranslatorController()->rejectDataItem($job_item, tmgmt_ensure_keys_array($matches['key']), $values);
- }
- }
- default:
- $data['#status'] = TMGMT_DATA_ITEM_STATE_PENDING;
- break;
- }
- if ($success) {
- $job_item->updateData($matches['key'], $data);
- // If a data item has been rejected and the job is in needs review state,
- // set back to active.
- if ($matches['action'] == 'reject' && $job_item->isNeedsReview()) {
- $job_item->active(FALSE);
- }
- }
- tmgmt_ui_write_request_messages($job_item->getJob());
- }
- /**
- * Ajax callback for the job item review form.
- */
- function tmgmt_ui_translation_review_form_ajax($form, &$form_state) {
- $key = array_slice($form_state['triggering_element']['#array_parents'], 0, 2);
- $render_data = drupal_array_get_nested_value($form, $key);
- tmgmt_ui_write_request_messages($form_state['item']->getJob());
- return drupal_render($render_data);
- }
- /**
- * Form callback for the reject confirm form.
- */
- function tmgmt_ui_translation_review_form_reject_confirm($form, &$form_state, TMGMTJobItem $job_item, $key) {
- // Path of job item review form.
- $path = explode('/', current_path());
- $path = implode('/', array_slice($path, 0, count($path) - 2));
- $args = array(
- '@data_item' => $job_item->getData(tmgmt_ensure_keys_array($key), '#label'),
- '@job_item' => $job_item->label(),
- );
- $form = confirm_form( $form, t('Confirm rejection of @data_item in @job_item', $args), $path, '');
- $form_state['item'] = $job_item;
- $form['key'] = array('#type' => 'value', '#value' => $key);
- $form['actions']['submit']['#name'] = 'reject-' . $key;
- $form['actions']['submit']['#submit'] = array('tmgmt_ui_translation_review_form_update_state', 'tmgmt_ui_translation_review_form_submit');
- $form = $job_item->getTranslatorController()->rejectForm($form, $form_state);
- return $form;
- }
- /**
- * @addtogroup tmgmt_ui_redirect_queue
- * @{
- */
- /**
- * Set a redirect queue that can then be worked through.
- *
- * @param $redirects
- * An array of redirect url's to be processed. For example checkout pages as
- * returned by tmgmt_ui_job_checkout_multiple().
- * @param $destination
- * A final destination to go to after the queue has been processed.
- */
- function tmgmt_ui_redirect_queue_set(array $redirects, $destination = NULL) {
- $_SESSION['tmgmt_ui']['redirect_queue'] = $redirects;
- $_SESSION['tmgmt_ui']['destination'] = $destination;
- }
- /**
- * Returns the redirect queue destination.
- *
- * This is the final destination after all queue items have been processed.
- *
- * @param $destination
- * The default destination that should be returned if none exists.
- *
- * @return
- * The stored destination if defined, otherwise the passed in default
- * destination.
- */
- function tmgmt_ui_redirect_queue_destination($destination = NULL) {
- if (!empty($_SESSION['tmgmt_ui']['destination'])) {
- $destination = $_SESSION['tmgmt_ui']['destination'];
- unset($_SESSION['tmgmt_ui']['destination']);
- return $destination;
- }
- return $destination;
- }
- /**
- * Returns the amount of entries in the redirect queue.
- *
- * @return
- * The amount of entries in the redirect queue.
- */
- function tmgmt_ui_redirect_queue_count() {
- if (!empty($_SESSION['tmgmt_ui']['redirect_queue'])) {
- return count($_SESSION['tmgmt_ui']['redirect_queue']);
- }
- return 0;
- }
- /**
- * Dequeues one redirect in the queue and returns that.
- *
- * @return
- * A redirect URL or NULL if the queue is empty.
- */
- function tmgmt_ui_redirect_queue_dequeue() {
- if (!empty($_SESSION['tmgmt_ui']['redirect_queue'])) {
- return array_shift($_SESSION['tmgmt_ui']['redirect_queue']);
- }
- }
- /**
- * @} End of "addtogroup tmgmt_ui_redirect_queue".
- */
- /**
- * Provides color legends for source statuses.
- */
- function tmgmt_ui_color_legend() {
- global $theme;
- drupal_add_css(drupal_get_path('module', 'tmgmt_ui') . '/css/tmgmt_ui.admin.css');
- if ($theme == 'seven') {
- drupal_add_css(drupal_get_path('module', 'tmgmt_ui') . '/css/tmgmt_ui.admin.seven.css');
- }
- $legends = array();
- $legends[] = array('legend' => t('Source Language'), 'color' => 'tmgmt-ui-icon-white');
- $legends[] = array('legend' => t('Not translated'), 'color' => 'tmgmt-ui-icon-grey');
- $legends[] = array('legend' => t('In progress'), 'color' => 'tmgmt-ui-icon-blue');
- $legends[] = array('legend' => t('Ready for review'), 'color' => 'tmgmt-ui-icon-yellow');
- $legends[] = array('legend' => t('Translated'), 'color' => 'tmgmt-ui-icon-green');
- $legends[] = array('legend' => t('Translation Outdated'), 'color' => 'tmgmt-ui-icon-orange');
- $output = '<div class="tmgmt-color-legend clearfix">';
- foreach ($legends as $legend) {
- $output .= '<div class="tmgmt-one-legend">
- <div class="tmgmt-legend-icon tmgmt-ui-icon tmgmt-ui-icon-10 ' .
- $legend['color'] . '"><span></span></div>
- <div class="tmgmt-legend-status">' . $legend['legend'] . '</div>
- </div>';
- }
- $output .= '</div>';
- return $output;
- }
- /**
- * Attempts to checkout a number of jobs and prepare the necessary redirects.
- *
- * @param array $form_state
- * Form state array, used to set the initial redirect.
- * @param array $jobs
- * Array of jobs to attempt checkout
- *
- * @ingroup tmgmt_job
- *
- * @see tmgmt_ui_job_checkout_multiple()
- */
- function tmgmt_ui_job_checkout_and_redirect(array &$form_state, array $jobs) {
- $redirects = tmgmt_ui_job_checkout_multiple($jobs);
- // If necessary, do a redirect.
- if ($redirects) {
- if (isset($_GET['destination'])) {
- // Remove existing destination, as that will prevent us from being
- // redirect to the job checkout page. Set the destination as the final
- // redirect instead.
- tmgmt_ui_redirect_queue_set($redirects, $_GET['destination']);
- unset($_GET['destination']);
- }
- else {
- tmgmt_ui_redirect_queue_set($redirects, current_path());
- }
- $form_state['redirect'] = tmgmt_ui_redirect_queue_dequeue();
- // Count of the job messages is one less due to the final redirect.
- drupal_set_message(format_plural(count($redirects), t('One job needs to be checked out.'), t('@count jobs need to be checked out.')));
- }
- }
- /**
- * Implements hook_help().
- */
- function tmgmt_ui_help($path, $arg) {
- $output = '';
- if (strpos($path, 'admin/tmgmt/sources') !== FALSE) {
- $output = '<div class="source-help-wrapper">' . tmgmt_ui_color_legend() . '</div>';
- }
- if ($path == 'admin/tmgmt/cart') {
- $output = '<p>' . t('The TMGMT cart is used to bundle text items from
- different sources into one translation job. Use the "Add to cart" button to
- add all selected items in any source list. <br/>From the cart page, you can
- request a translation of all selected elements in the cart into any available
- language. One translation job will be created for each language pair involved.')
- . '</p>';
- }
- return $output;
- }
|