/** * Returns an array of the changes from $old text to the $new one * * This is just slightly customized version of Paul's Simple Diff Algorithm. * Given two arrays of chunks (words), the function returns an array of the changes * leading from $old to $new. * * @author Paul Butler * @copyright (C) Paul Butler 2007 <http://www.paulbutler.org/> * @license May be used and distributed under the zlib/libpng license * @link https://github.com/paulgb/simplediff * @version 26f97a48598d7b306ae9 * @param array $old array of words * @param array $new array of words * @return array */ function local_amos_simplediff(array $old, array $new) { $maxlen = 0; foreach ($old as $oindex => $ovalue) { $nkeys = array_keys($new, $ovalue); foreach ($nkeys as $nindex) { $matrix[$oindex][$nindex] = isset($matrix[$oindex - 1][$nindex - 1]) ? $matrix[$oindex - 1][$nindex - 1] + 1 : 1; if ($matrix[$oindex][$nindex] > $maxlen) { $maxlen = $matrix[$oindex][$nindex]; $omax = $oindex + 1 - $maxlen; $nmax = $nindex + 1 - $maxlen; } } } if ($maxlen == 0) { return array(array('d' => $old, 'i' => $new)); } return array_merge(local_amos_simplediff(array_slice($old, 0, $omax), array_slice($new, 0, $nmax)), array_slice($new, $nmax, $maxlen), local_amos_simplediff(array_slice($old, $omax + $maxlen), array_slice($new, $nmax + $maxlen))); }
/** * Renders the stage * * @param local_amos_stage $stage * @return string */ protected function render_local_amos_stage(local_amos_stage $stage) { global $CFG; $table = new html_table(); $table->id = 'amosstage'; $table->head = array(get_string('stagestring', 'local_amos'), get_string('stageoriginal', 'local_amos'), get_string('stagelang', 'local_amos'), get_string('stagetranslation', 'local_amos') . $this->help_icon('stagetranslation', 'local_amos')); $table->colclasses = array('stringinfo', 'original', 'lang', 'translation'); $standard = array(); foreach (local_amos_standard_plugins() as $plugins) { $standard = array_merge($standard, $plugins); } $committable = 0; foreach ($stage->strings as $string) { $cells = array(); // string identification if (isset($standard[$string->component])) { $componentname = $standard[$string->component]; } else { $componentname = $string->component; } $stringinfo = html_writer::tag('span', $string->version, array('class' => 'version')); $stringinfo .= ' [' . html_writer::tag('span', $string->stringid, array('class' => 'stringid')) . ',' . html_writer::tag('span', $componentname, array('class' => 'component')) . ']'; $cells[0] = new html_table_cell($stringinfo); // original of the string $cells[1] = new html_table_cell(html_writer::tag('div', self::add_breaks(s($string->original)), array('class' => 'preformatted'))); // the language in which the original is displayed $cells[2] = new html_table_cell($string->language); // the current and the new translation $unstageurl = new moodle_url('/local/amos/stage.php', array('unstage' => $string->stringid, 'component' => $string->component, 'branch' => $string->branch, 'lang' => $string->language)); $unstagebutton = $this->single_button($unstageurl, get_string('unstage', 'local_amos'), 'post', array('class' => 'singlebutton protected unstagebutton')); if ($string->deleted) { // removal of the string $t = self::add_breaks(s($string->current)); $t = html_writer::tag('div', $t, array('class' => 'preformatted')); $cells[3] = new html_table_cell($t . $unstagebutton); if ($string->committable) { $committable++; $cells[3]->attributes['class'] .= 'committable removal'; } else { $cells[3]->attributes['class'] .= 'uncommittable removal'; } } else { if (trim($string->current) === trim($string->new)) { // no difference $t = self::add_breaks(s($string->current)); $t = html_writer::tag('div', $t, array('class' => 'preformatted')); $cells[3] = new html_table_cell($t . $unstagebutton); $cells[3]->attributes['class'] .= ' uncommittable nodiff'; } else { if (is_null($string->current)) { // new translation $t = $t = self::add_breaks(s($string->new)); $t = html_writer::tag('div', $t, array('class' => 'preformatted')); $cells[3] = new html_table_cell($t . $unstagebutton); if ($string->committable) { $cells[3]->attributes['class'] .= ' committable new'; $committable++; } if (!$string->committable) { $cells[3]->attributes['class'] .= ' uncommittable new'; } } else { // there is a difference $c = s($string->current); $n = s($string->new); $x1 = explode(' ', $c); $x2 = explode(' ', $n); $t = ''; $diff = local_amos_simplediff($x1, $x2); $numd = 0; $numi = 0; foreach ($diff as $k) { // $diff is a sequence of chunks (words) $k if (is_array($k)) { if (!empty($k['d'])) { $kd = implode(' ', $k['d']); if (!empty($kd)) { $t .= '<del>' . $kd . '</del> '; $numd += count($k['d']); } } if (!empty($k['i'])) { $ki = implode(' ', $k['i']); if (!empty($ki)) { $t .= '<ins>' . $ki . '</ins> '; $numi += count($k['i']); } } } else { $t .= $k . ' '; } } if ($numi == 0 or $numd == 0 or $numd == 1 and $numi == 1) { $cstyle = 'display:none;'; $nstyle = 'display:none;'; $tstyle = 'display:block;'; } else { $cstyle = 'display:block;'; $nstyle = 'display:block;'; $tstyle = 'display:none;'; } $n = html_writer::tag('ins', $n); $n = html_writer::tag('div', self::add_breaks($n), array('class' => 'preformatted stringtext new', 'style' => $nstyle)); $c = html_writer::tag('del', $c); $c = html_writer::tag('div', self::add_breaks($c), array('class' => 'preformatted stringtext current', 'style' => $cstyle)); $t = html_writer::tag('div', self::add_breaks($t), array('class' => 'preformatted stringtext diff', 'style' => $tstyle)); $difflink = html_writer::tag('div', '', array('class' => 'diffmode')); $cells[3] = new html_table_cell($difflink . $n . $c . $t . $unstagebutton); if ($string->committable) { $cells[3]->attributes['class'] .= ' committable diff'; $committable++; } if (!$string->committable) { $cells[3]->attributes['class'] .= ' uncommittable diff'; } } } } $row = new html_table_row($cells); $table->data[] = $row; } $table = html_writer::table($table); $propagateform = ''; $propagateform .= html_writer::empty_tag('input', array('name' => 'sesskey', 'value' => sesskey(), 'type' => 'hidden')); $propagateform .= html_writer::empty_tag('input', array('name' => 'propagate', 'value' => 1, 'type' => 'hidden')); foreach (mlang_version::list_all() as $version) { if ($version->code < 2000) { continue; } $checkbox = html_writer::checkbox('ver[]', $version->code, true, $version->label); $propagateform .= html_writer::tag('div', $checkbox, array('class' => 'labelled_checkbox')); } $propagateform .= html_writer::empty_tag('input', array('value' => get_string('propagaterun', 'local_amos'), 'type' => 'submit')); $propagateform = html_writer::tag('div', $propagateform); $propagateform = html_writer::tag('form', $propagateform, array('method' => 'post', 'action' => $CFG->wwwroot . '/local/amos/stage.php')); $propagateform .= html_writer::tag('legend', get_string('propagate', 'local_amos') . $this->help_icon('propagate', 'local_amos')); $propagateform = html_writer::tag('fieldset', $propagateform, array('class' => 'propagateformwrapper protected')); $commitform = html_writer::label(get_string('commitmessage', 'local_amos'), 'commitmessage', false); $commitform .= html_writer::empty_tag('img', array('src' => $this->pix_url('req'), 'title' => 'Required', 'alt' => 'Required', 'class' => 'req')); $commitform .= html_writer::empty_tag('br'); $commitform .= html_writer::tag('textarea', s($stage->presetmessage), array('id' => 'commitmessage', 'name' => 'message')); $commitform .= html_writer::empty_tag('input', array('name' => 'sesskey', 'value' => sesskey(), 'type' => 'hidden')); $button = html_writer::empty_tag('input', array('value' => get_string('commitbutton', 'local_amos'), 'type' => 'submit')); $button = html_writer::tag('div', $button); $commitform = html_writer::tag('div', $commitform . $button); $commitform = html_writer::tag('form', $commitform, array('method' => 'post', 'action' => $CFG->wwwroot . '/local/amos/stage.php')); $commitform .= html_writer::tag('legend', get_string('commitstage', 'local_amos') . $this->help_icon('commitstage', 'local_amos')); $commitform = html_writer::tag('fieldset', $commitform, array('class' => 'commitformwrapper protected')); $a = new stdClass(); $a->time = userdate(time(), get_string('strftimedaydatetime', 'langconfig')); $stashtitle = get_string('stashtitledefault', 'local_amos', $a); $stashform = html_writer::label(get_string('stashtitle', 'local_amos'), 'stashtitle', true); $stashform .= html_writer::empty_tag('input', array('name' => 'sesskey', 'value' => sesskey(), 'type' => 'hidden')); $stashform .= html_writer::empty_tag('input', array('name' => 'new', 'value' => 1, 'type' => 'hidden')); $stashform .= html_writer::empty_tag('input', array('name' => 'name', 'value' => $stashtitle, 'type' => 'text', 'size' => 50, 'id' => 'stashtitle', 'maxlength' => 255)); $stashform .= html_writer::empty_tag('input', array('value' => get_string('stashpush', 'local_amos'), 'type' => 'submit')); $stashform = html_writer::tag('div', $stashform); $stashform = html_writer::tag('form', $stashform, array('method' => 'post', 'action' => $CFG->wwwroot . '/local/amos/stash.php')); $stashform = html_writer::tag('div', $stashform, array('class' => 'stashformwrapper')); $submiturl = new moodle_url('/local/amos/stage.php', array('submit' => 1)); $submitbutton = $this->single_button($submiturl, get_string('stagesubmit', 'local_amos'), 'post', array('class' => 'singlebutton submit')); $pruneurl = new moodle_url('/local/amos/stage.php', array('prune' => 1)); $prunebutton = $this->single_button($pruneurl, get_string('stageprune', 'local_amos'), 'post', array('class' => 'singlebutton protected prune')); $rebaseurl = new moodle_url('/local/amos/stage.php', array('rebase' => 1)); $rebasebutton = $this->single_button($rebaseurl, get_string('stagerebase', 'local_amos'), 'post', array('class' => 'singlebutton protected rebase')); $unstageallurl = new moodle_url('/local/amos/stage.php', array('unstageall' => 1)); $unstageallbutton = $this->single_button($unstageallurl, get_string('stageunstageall', 'local_amos'), 'post', array('class' => 'singlebutton protected unstageall')); $i = 0; foreach ($stage->filterfields->fver as $fver) { $params['fver[' . $i . ']'] = $fver; $i++; } $i = 0; foreach ($stage->filterfields->flng as $flng) { $params['flng[' . $i . ']'] = $flng; $i++; } $i = 0; foreach ($stage->filterfields->fcmp as $fcmp) { $params['fcmp[' . $i . ']'] = $fcmp; $i++; } $params['fstg'] = 1; $params['__lazyform_amosfilter'] = 1; $editurl = new moodle_url('/local/amos/view.php', $params); $editbutton = $this->single_button($editurl, get_string('stageedit', 'local_amos'), 'post', array('class' => 'singlebutton edit')); if (empty($stage->strings)) { $output = $this->heading(get_string('stagestringsnone', 'local_amos'), 2, 'main', 'numberofstagedstrings'); if ($stage->importform) { $legend = html_writer::tag('legend', get_string('importfile', 'local_amos') . $this->help_icon('importfile', 'local_amos')); ob_start(); $stage->importform->display(); $importform = ob_get_contents(); ob_end_clean(); $output .= html_writer::tag('fieldset', $legend . $importform, array('class' => 'wrappedmform importform')); } if ($stage->mergeform) { $legend = html_writer::tag('legend', get_string('mergestrings', 'local_amos') . $this->help_icon('mergestrings', 'local_amos')); ob_start(); $stage->mergeform->display(); $mergeform = ob_get_contents(); ob_end_clean(); $output .= html_writer::tag('fieldset', $legend . $mergeform, array('class' => 'wrappedmform mergeform')); } if ($stage->diffform) { $legend = html_writer::tag('legend', get_string('diffstrings', 'local_amos') . $this->help_icon('diffstrings', 'local_amos')); ob_start(); $stage->diffform->display(); $diffform = ob_get_contents(); ob_end_clean(); $output .= html_writer::tag('fieldset', $legend . $diffform, array('class' => 'wrappedmform diffform')); } if ($stage->executeform) { $legend = html_writer::tag('legend', get_string('script', 'local_amos') . $this->help_icon('script', 'local_amos')); ob_start(); $stage->executeform->display(); $executeform = ob_get_contents(); ob_end_clean(); $output .= html_writer::tag('fieldset', $legend . $executeform, array('class' => 'wrappedmform executeform')); } } else { $output = ''; if (!empty($stage->stagedcontribution)) { $output .= $this->heading_with_help(get_string('contribstaged', 'local_amos', $stage->stagedcontribution), 'contribstagedinfo', 'local_amos'); } $a = (object) array('staged' => count($stage->strings), 'committable' => $committable); if ($committable) { $output .= $this->heading(get_string('stagestringssome', 'local_amos', $a), 2, 'main', 'numberofstagedstrings'); } else { $output .= $this->heading(get_string('stagestringsnocommit', 'local_amos', $a), 2, 'main', 'numberofstagedstrings'); } unset($a); $justpropagated = optional_param('justpropagated', null, PARAM_INT); // usability hack to hide the propagator just after it was used if (is_null($justpropagated)) { $output .= $propagateform; } else { if ($justpropagated == 0) { $output .= $this->heading(get_string('propagatednone', 'local_amos')); } else { $output .= $this->heading(get_string('propagatedsome', 'local_amos', $justpropagated)); } } if ($committable) { $output .= $commitform; } $legend = html_writer::tag('legend', get_string('stageactions', 'local_amos') . $this->help_icon('stageactions', 'local_amos')); $actionbuttons = $legend . $submitbutton . $editbutton; if ($committable) { $actionbuttons .= $prunebutton . $rebasebutton; } $actionbuttons .= $unstageallbutton; $output .= html_writer::tag('fieldset', $actionbuttons, array('class' => 'actionbuttons')); $legend = html_writer::tag('legend', get_string('stashactions', 'local_amos') . $this->help_icon('stashactions', 'local_amos')); $output .= html_writer::tag('fieldset', $legend . $stashform, array('class' => 'actionbuttons')); $output .= $table; } $output = html_writer::tag('div', $output, array('class' => 'stagewrapper')); return $output; }