= pointers.pop()
58 | let event2: PointerEvent
59 | while ((event2 = pointers.pop())) {
60 | event1 = {
61 | clientX: (event2.clientX - event1.clientX) / 2 + event1.clientX,
62 | clientY: (event2.clientY - event1.clientY) / 2 + event1.clientY
63 | }
64 | }
65 | return event1
66 | }
67 |
68 | /**
69 | * Calculates the distance between two points
70 | * for pinch zooming.
71 | * Limits to the first 2
72 | */
73 | export function getDistance(pointers: PointerEvent[]) {
74 | if (pointers.length < 2) {
75 | return 0
76 | }
77 | const event1 = pointers[0]
78 | const event2 = pointers[1]
79 | return Math.sqrt(
80 | Math.pow(Math.abs(event2.clientX - event1.clientX), 2) +
81 | Math.pow(Math.abs(event2.clientY - event1.clientY), 2)
82 | )
83 | }
84 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## How to contribute to DataScribe
2 |
3 | Thanks for your interest in contributing to DataScribe (and to the Omeka community more generally).
4 |
5 | #### **Did you find a bug?**
6 |
7 | * Please check to see if the bug was already reported by checking the open [Issues](https://github.com/chnm/Datascribe-module/issues).
8 |
9 | * If you're unable to find an open issue on the bug, [open a new issue](https://github.com/chnm/Datascribe-module/issues/new). Include a title that briefly describes the issue as well as a longer, clear description of the bug.
10 |
11 | * A good bug description is likely to include
12 | * what browser version you are using (e.g. Safari Version 16.6)
13 | * what page or pages you were on when the error occurred
14 | * what, if any, actions you took that resulted in the bug
15 | * any error message produced by the system
16 |
17 | #### **Did you fix a bug?**
18 |
19 | * Please check to see if the bug was already reported by checking the open [Issues](https://github.com/chnm/Datascribe-module/issues).
20 |
21 | * If you're unable to find an open issue on the bug, please [open a new issue](https://github.com/chnm/Datascribe-module/issues/new) as described above.
22 |
23 | * If an open issue already exists, go ahead and open a new GitHub pull request with the bug fix.
24 |
25 | * The pull request description should clearly describe the problem and solution with a reference to the appropriate open issue.
26 |
27 | #### **Do you want to add a new feature?**
28 |
29 | * Please contact us at [chnm@gmu.edu](mailto:chnm@gmu.edu) with the subject line: Proposed DataScribe Contribution and you will be forwarded to a member of the team to discuss the feature development.
30 |
31 | * Do not open an issue on GitHub until you have talked with a member of the team.
32 |
33 | #### **Do you have questions about the code?**
34 |
35 | * You can ask general questions in the Omeka community forum. You may also contact us at [chnm@gmu.edu](mailto:chnm@gmu.edu) with the subject line: Question about DataScribe.
36 |
37 | * Do not open an issue on GitHub with questions about the code or general tech support requests.
38 |
39 | #### **Do you want to contribute to the documentation?**
40 |
41 | * If you're interested in contributing to the documentation, please contact us at [chnm@gmu.edu](mailto:chnm@gmu.edu) with the subject line: DataScribe Documentation.
42 |
43 | * We would particularly welcome people who are interested in helping us translate our documentation into additional languages.
--------------------------------------------------------------------------------
/view/datascribe/admin/dataset/form-sidebars.phtml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
18 |
19 |
25 |
26 |
32 |
--------------------------------------------------------------------------------
/src/DatascribeDataType/Unknown.php:
--------------------------------------------------------------------------------
1 | name = $name;
12 | }
13 |
14 | public function getLabel(): string
15 | {
16 | return '[Unknown]'; // @translate
17 | }
18 |
19 | public function addFieldElements(Fieldset $fieldset, array $fieldData): void
20 | {
21 | $element = new Element\Text('data_type');
22 | $element->setLabel('Unknown data type'); // @translate
23 | $element->setValue($this->name);
24 | $element->setAttribute('disabled', true);
25 | $fieldset->add($element);
26 |
27 | $element = new Element\Textarea('field_data');
28 | $element->setLabel('Field data'); // @translate
29 | $element->setValue(json_encode($fieldData, JSON_PRETTY_PRINT));
30 | $element->setAttributes([
31 | 'disabled' => true,
32 | 'rows' => 8,
33 | ]);
34 | $fieldset->add($element);
35 |
36 | // We need to add an unused element here so the "data" fieldset appears
37 | // in POST data. Otherwise the API request will not validate.
38 | $fieldset->add(new Element\Hidden('unknown'));
39 | }
40 |
41 | public function getFieldDataFromUserData(array $userData): array
42 | {
43 | return [];
44 | }
45 |
46 | public function fieldDataIsValid(array $fieldData): bool
47 | {
48 | return true;
49 | }
50 |
51 | public function addValueElements(Fieldset $fieldset, array $fieldData, ?string $valueText): void
52 | {
53 | $element = new Element\Text('data_type');
54 | $element->setLabel('Unknown data type'); // @translate
55 | $element->setValue($this->name);
56 | $element->setAttribute('disabled', true);
57 | $fieldset->add($element);
58 |
59 | $element = new Element\Textarea('value_text');
60 | $element->setLabel('Value text'); // @translate
61 | $element->setValue($valueText);
62 | $element->setAttributes([
63 | 'disabled' => true,
64 | 'rows' => 8,
65 | ]);
66 | $fieldset->add($element);
67 | }
68 |
69 | public function getValueTextFromUserData(array $userData): ?string
70 | {
71 | return null;
72 | }
73 |
74 | public function valueTextIsValid(array $fieldData, ?string $valueText): bool
75 | {
76 | // Note that we assume all "Unknown" text is valid so it persists until
77 | // an administrator corrects or deletes the field.
78 | return true;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Form/ItemBatchForm.php:
--------------------------------------------------------------------------------
1 | getOption('project');
9 |
10 | $valueOptions = $this->getLockToOtherValueOptions([
11 | 'unlock' => 'Unlock', // @translate
12 | 'lock' => 'Lock to me', // @translate
13 | ], $project);
14 | $this->add([
15 | 'type' => 'select',
16 | 'name' => 'lock_action',
17 | 'options' => [
18 | 'label' => 'Lock action', // @translate
19 | 'empty_option' => '',
20 | 'value_options' => $valueOptions,
21 | ],
22 | 'attributes' => [
23 | 'class' => 'chosen-select',
24 | 'data-placeholder' => '[No change]', // @translate
25 | ],
26 | ]);
27 | $this->add([
28 | 'type' => 'select',
29 | 'name' => 'review_action',
30 | 'options' => [
31 | 'label' => 'Review action', // @translate
32 | 'empty_option' => '',
33 | 'value_options' => [
34 | 'approved' => 'Mark as approved', // @translate
35 | 'not_approved' => 'Mark as not approved', // @translate
36 | 'not_reviewed' => 'Mark as not reviewed', // @translate
37 | ],
38 | ],
39 | 'attributes' => [
40 | 'class' => 'chosen-select',
41 | 'data-placeholder' => '[No change]', // @translate
42 | ],
43 | ]);
44 | $this->add([
45 | 'type' => 'select',
46 | 'name' => 'priority_action',
47 | 'options' => [
48 | 'label' => 'Priority action', // @translate
49 | 'empty_option' => '',
50 | 'value_options' => [
51 | 'prioritized' => 'Mark as prioritized', // @translate
52 | 'not_prioritized' => 'Mark as not prioritized', // @translate
53 | ],
54 | ],
55 | 'attributes' => [
56 | 'class' => 'chosen-select',
57 | 'data-placeholder' => '[No change]', // @translate
58 | ],
59 | ]);
60 |
61 | $inputFilter = $this->getInputFilter();
62 | $inputFilter->add([
63 | 'name' => 'lock_action',
64 | 'allow_empty' => true,
65 | ]);
66 | $inputFilter->add([
67 | 'name' => 'review_action',
68 | 'allow_empty' => true,
69 | ]);
70 | $inputFilter->add([
71 | 'name' => 'priority_action',
72 | 'allow_empty' => true,
73 | ]);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/Api/Representation/DatascribeFieldRepresentation.php:
--------------------------------------------------------------------------------
1 | setServiceLocator($services);
23 | $this->field = $field;
24 | }
25 |
26 | public function jsonSerialize(): array
27 | {
28 | }
29 |
30 | public function id()
31 | {
32 | return $this->field->getId();
33 | }
34 |
35 | public function name(array $options = [])
36 | {
37 | // Set default options.
38 | $options['length'] ??= null;
39 | $options['trim_marker'] ??= null;
40 |
41 | $name = $this->field->getName();
42 | $nameLength = mb_strlen($name);
43 | if ($options['length']) {
44 | $name = mb_substr($name, 0, (int) $options['length']);
45 | }
46 | if ($options['trim_marker'] && $nameLength > mb_strlen($name)) {
47 | $name .= $options['trim_marker'];
48 | }
49 | return $name;
50 | }
51 |
52 | public function description()
53 | {
54 | return $this->field->getDescription();
55 | }
56 |
57 | public function dataset()
58 | {
59 | return $this->getAdapter('datascribe_datasets')
60 | ->getRepresentation($this->resource->getDataset());
61 | }
62 |
63 | public function position()
64 | {
65 | return $this->field->getPosition();
66 | }
67 |
68 | public function isPrimary()
69 | {
70 | return $this->field->getIsPrimary();
71 | }
72 |
73 | public function isRequired()
74 | {
75 | return $this->field->getIsRequired();
76 | }
77 |
78 | public function dataType()
79 | {
80 | return $this->field->getDataType();
81 | }
82 |
83 | public function dataTypeService()
84 | {
85 | return $this->getServiceLocator()
86 | ->get('Datascribe\DataTypeManager')
87 | ->get($this->dataType());
88 | }
89 |
90 | public function dataTypeIsUnknown()
91 | {
92 | return ($this->dataTypeService() instanceof Unknown);
93 | }
94 |
95 | public function data()
96 | {
97 | return $this->field->getData();
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/Form/Element/MinuteSelect.php:
--------------------------------------------------------------------------------
1 | '00',
12 | 1 => '01',
13 | 2 => '02',
14 | 3 => '03',
15 | 4 => '04',
16 | 5 => '05',
17 | 6 => '06',
18 | 7 => '07',
19 | 8 => '08',
20 | 9 => '09',
21 | 10 => '10',
22 | 11 => '11',
23 | 12 => '12',
24 | 13 => '13',
25 | 14 => '14',
26 | 15 => '15',
27 | 16 => '16',
28 | 17 => '17',
29 | 18 => '18',
30 | 19 => '19',
31 | 20 => '20',
32 | 21 => '21',
33 | 22 => '22',
34 | 23 => '23',
35 | 24 => '24',
36 | 25 => '25',
37 | 26 => '26',
38 | 27 => '27',
39 | 28 => '28',
40 | 29 => '29',
41 | 30 => '30',
42 | 31 => '31',
43 | 32 => '32',
44 | 33 => '33',
45 | 34 => '34',
46 | 35 => '35',
47 | 36 => '36',
48 | 37 => '37',
49 | 38 => '38',
50 | 39 => '39',
51 | 40 => '40',
52 | 41 => '41',
53 | 42 => '42',
54 | 43 => '43',
55 | 44 => '44',
56 | 45 => '45',
57 | 46 => '46',
58 | 47 => '47',
59 | 48 => '48',
60 | 49 => '49',
61 | 50 => '50',
62 | 51 => '51',
63 | 52 => '52',
64 | 53 => '53',
65 | 54 => '54',
66 | 55 => '55',
67 | 56 => '56',
68 | 57 => '57',
69 | 58 => '58',
70 | 59 => '59',
71 | ];
72 |
73 | public function __construct($name = null, $options = [])
74 | {
75 | parent::__construct($name, $options);
76 |
77 | $fieldData = $this->getOption('datascribe_field_data');
78 |
79 | $this->setValueOptions(self::MINUTES);
80 | $this->setEmptyOption('');
81 | }
82 |
83 | public function getValidators()
84 | {
85 | $fieldData = $this->getOption('datascribe_field_data');
86 |
87 | $validators = [];
88 | $validators[] = new Validator\Between(['min' => 0, 'max' => 59, 'inclusive' => true]);
89 | $validators[] = new Validator\Regex(['pattern' => '/\d+/']);
90 |
91 | return $validators;
92 | }
93 |
94 | public function getInputSpecification(): array
95 | {
96 | return [
97 | 'name' => $this->getName(),
98 | 'required' => null,
99 | 'validators' => $this->getValidators(),
100 | 'filters' => [],
101 | ];
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/Form/Element/SecondSelect.php:
--------------------------------------------------------------------------------
1 | '00',
12 | 1 => '01',
13 | 2 => '02',
14 | 3 => '03',
15 | 4 => '04',
16 | 5 => '05',
17 | 6 => '06',
18 | 7 => '07',
19 | 8 => '08',
20 | 9 => '09',
21 | 10 => '10',
22 | 11 => '11',
23 | 12 => '12',
24 | 13 => '13',
25 | 14 => '14',
26 | 15 => '15',
27 | 16 => '16',
28 | 17 => '17',
29 | 18 => '18',
30 | 19 => '19',
31 | 20 => '20',
32 | 21 => '21',
33 | 22 => '22',
34 | 23 => '23',
35 | 24 => '24',
36 | 25 => '25',
37 | 26 => '26',
38 | 27 => '27',
39 | 28 => '28',
40 | 29 => '29',
41 | 30 => '30',
42 | 31 => '31',
43 | 32 => '32',
44 | 33 => '33',
45 | 34 => '34',
46 | 35 => '35',
47 | 36 => '36',
48 | 37 => '37',
49 | 38 => '38',
50 | 39 => '39',
51 | 40 => '40',
52 | 41 => '41',
53 | 42 => '42',
54 | 43 => '43',
55 | 44 => '44',
56 | 45 => '45',
57 | 46 => '46',
58 | 47 => '47',
59 | 48 => '48',
60 | 49 => '49',
61 | 50 => '50',
62 | 51 => '51',
63 | 52 => '52',
64 | 53 => '53',
65 | 54 => '54',
66 | 55 => '55',
67 | 56 => '56',
68 | 57 => '57',
69 | 58 => '58',
70 | 59 => '59',
71 | ];
72 |
73 | public function __construct($name = null, $options = [])
74 | {
75 | parent::__construct($name, $options);
76 |
77 | $fieldData = $this->getOption('datascribe_field_data');
78 |
79 | $this->setValueOptions(self::SECONDS);
80 | $this->setEmptyOption('');
81 | }
82 |
83 | public function getValidators()
84 | {
85 | $fieldData = $this->getOption('datascribe_field_data');
86 |
87 | $validators = [];
88 | $validators[] = new Validator\Between(['min' => 0, 'max' => 59, 'inclusive' => true]);
89 | $validators[] = new Validator\Regex(['pattern' => '/\d+/']);
90 |
91 | return $validators;
92 | }
93 |
94 | public function getInputSpecification(): array
95 | {
96 | return [
97 | 'name' => $this->getName(),
98 | 'required' => null,
99 | 'validators' => $this->getValidators(),
100 | 'filters' => [],
101 | ];
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/view/datascribe/admin/record/previous-next-records.phtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 | | translate('Record #'); ?> |
11 | fields() as $field): ?>
12 | isPrimary() ? ' class="primary-field"' : ''; ?>>name([
13 | 'length' => 20,
14 | 'trim_marker' => '...',
15 | ]); ?> |
16 |
17 |
18 |
19 |
20 |
21 | values(); ?>
22 |
23 | | id(); ?> |
24 | fields() as $field): ?>
25 | id()] ?? null; ?>
26 | isPrimary() ? ' class="primary-field"' : ''; ?>>
27 | dataTypeIsUnknown()): ?>
28 | translate('unknown'); ?>
29 | isRequired() && (null === $value)): ?>
30 | translate('invalid'); ?>
31 |
32 | translate('null'); ?>
33 |
34 | displayText([
35 | 'length' => 50,
36 | 'trim_marker' => '...',
37 | 'if_invalid_return' => sprintf('%s', $this->translate('invalid')),
38 | 'if_empty_return' => sprintf('%s', $this->translate('empty')),
39 | 'if_null_return' => sprintf('%s', $this->translate('null')),
40 | 'if_unknown_return' => sprintf('%s', $this->translate('unknown')),
41 | ]); ?>
42 |
43 | |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/src/DatascribeDataType/AbstractSelection.php:
--------------------------------------------------------------------------------
1 | setLabel('Selection label'); // @translate
13 | $element->setValue($fieldData['label'] ?? null);
14 | $fieldset->add($element);
15 |
16 | $element = new Element\Textarea('options');
17 | $element->setLabel('Options'); // @translate
18 | $element->setOption('info', 'The selection options separated by new lines.'); // @translate
19 | $element->setAttribute('rows', 10);
20 | $element->setValue(implode("\n", $fieldData['options'] ?? []));
21 | $fieldset->add($element);
22 |
23 | $element = new Element\Text('default_value');
24 | $element->setLabel('Default value'); // @translate
25 | $element->setValue($fieldData['default_value'] ?? null);
26 | $fieldset->add($element);
27 | }
28 |
29 | public function getFieldDataFromUserData(array $userData): array
30 | {
31 | $fieldData = [];
32 | if (isset($userData['options'])) {
33 | // The user data is usually a new line-delimited string, but it is
34 | // an array if it originates from form import.
35 | if (is_array($userData['options'])) {
36 | $options = $userData['options'];
37 | } elseif (preg_match('/^.+$/s', $userData['options'])) {
38 | $options = explode("\n", $userData['options']);
39 | } else {
40 | $options = [];
41 | }
42 | $options = array_map('trim', $options);
43 | $options = array_filter($options);
44 | $options = array_unique($options);
45 | $fieldData['options'] = $options;
46 | } else {
47 | $fieldData['options'] = [];
48 | }
49 | $fieldData['default_value'] =
50 | (isset($userData['default_value']) && preg_match('/^.+$/', $userData['default_value']))
51 | ? $userData['default_value'] : null;
52 | $fieldData['label'] =
53 | (isset($userData['label']) && preg_match('/^.+$/', $userData['label']))
54 | ? $userData['label'] : null;
55 | return $fieldData;
56 | }
57 |
58 | public function fieldDataIsValid(array $fieldData): bool
59 | {
60 | // Invalid data was filtered out in self::getFieldDataFromUserData().
61 | return true;
62 | }
63 |
64 | public function getValueTextFromUserData(array $userData): ?string
65 | {
66 | $text = null;
67 | if (isset($userData['value']) && is_string($userData['value']) && ('' !== $userData['value'])) {
68 | $text = $userData['value'];
69 | }
70 | return $text;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/view/datascribe/admin/record/show-details.phtml:
--------------------------------------------------------------------------------
1 | translate('Record metadata'); ?>
2 |
6 |
20 |
29 |
46 |
50 |
54 |
58 |
62 |
--------------------------------------------------------------------------------
/src/Api/Representation/DatascribeProjectRepresentation.php:
--------------------------------------------------------------------------------
1 | owner();
16 | $createdBy = $this->createdBy();
17 | $modifiedBy = $this->modifiedBy();
18 | $modified = $this->modified();
19 | return [
20 | 'o-module-datascribe:name' => $this->name(),
21 | 'o-module-datascribe:description' => $this->description(),
22 | 'o:is_public' => $this->isPublic(),
23 | 'o:created' => $this->getDateTime($this->created()),
24 | 'o:modified' => $modified ? $this->getDateTime($modified) : null,
25 | 'o:owner' => $owner ? $owner->getReference() : null,
26 | 'o-module-datascribe:created_by' => $createdBy ? $createdBy->getReference() : null,
27 | 'o-module-datascribe:modified_by' => $modifiedBy ? $modifiedBy->getReference() : null,
28 | 'o-module-datascribe:user' => $this->users(),
29 | ];
30 | }
31 |
32 | public function adminUrl($action = null, $canonical = false)
33 | {
34 | $url = $this->getViewHelper('Url');
35 | return $url(
36 | 'admin/datascribe-project-id',
37 | [
38 | 'action' => $action,
39 | 'project-id' => $this->resource->getId(),
40 | ],
41 | ['force_canonical' => $canonical]
42 | );
43 | }
44 |
45 | public function name()
46 | {
47 | return $this->resource->getName();
48 | }
49 |
50 | public function description()
51 | {
52 | return $this->resource->getDescription();
53 | }
54 |
55 | public function isPublic()
56 | {
57 | return $this->resource->getIsPublic();
58 | }
59 |
60 | public function created()
61 | {
62 | return $this->resource->getCreated();
63 | }
64 |
65 | public function modified()
66 | {
67 | return $this->resource->getModified();
68 | }
69 |
70 | public function owner()
71 | {
72 | return $this->getAdapter('users')
73 | ->getRepresentation($this->resource->getOwner());
74 | }
75 |
76 | public function createdBy()
77 | {
78 | return $this->getAdapter('users')
79 | ->getRepresentation($this->resource->getCreatedBy());
80 | }
81 |
82 | public function modifiedBy()
83 | {
84 | return $this->getAdapter('users')
85 | ->getRepresentation($this->resource->getModifiedBy());
86 | }
87 |
88 | public function users()
89 | {
90 | $users = [];
91 | foreach ($this->resource->getUsers() as $userId => $user) {
92 | $users[$userId] = new DatascribeUserRepresentation($user, $this->getServiceLocator());
93 | }
94 | return $users;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/Entity/DatascribeValue.php:
--------------------------------------------------------------------------------
1 | field = $field;
80 | }
81 |
82 | public function getField(): DatascribeField
83 | {
84 | return $this->field;
85 | }
86 |
87 | public function setRecord(DatascribeRecord $record): void
88 | {
89 | $this->record = $record;
90 | }
91 |
92 | public function getRecord(): DatascribeRecord
93 | {
94 | return $this->record;
95 | }
96 |
97 | public function setIsInvalid(bool $isInvalid): void
98 | {
99 | $this->isInvalid = $isInvalid;
100 | }
101 |
102 | public function getIsInvalid(): bool
103 | {
104 | return $this->isInvalid;
105 | }
106 |
107 | public function setIsMissing(bool $isMissing): void
108 | {
109 | $this->isMissing = $isMissing;
110 | }
111 |
112 | public function getIsMissing(): ?bool
113 | {
114 | return $this->isMissing;
115 | }
116 |
117 | public function setIsIllegible(bool $isIllegible): void
118 | {
119 | $this->isIllegible = $isIllegible;
120 | }
121 |
122 | public function getIsIllegible(): ?bool
123 | {
124 | return $this->isIllegible;
125 | }
126 |
127 | public function setText(?string $text): void
128 | {
129 | $this->text = $text;
130 | }
131 |
132 | public function getText(): ?string
133 | {
134 | return $this->text;
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/src/Entity/TraitOwnership.php:
--------------------------------------------------------------------------------
1 | owner = $owner;
70 | }
71 |
72 | public function getOwner(): ?User
73 | {
74 | return $this->owner;
75 | }
76 |
77 | public function setCreatedBy(?User $createdBy = null): void
78 | {
79 | $this->createdBy = $createdBy;
80 | }
81 |
82 | public function getCreatedBy(): ?User
83 | {
84 | return $this->createdBy;
85 | }
86 |
87 | public function setModifiedBy(?User $modifiedBy = null): void
88 | {
89 | $this->modifiedBy = $modifiedBy;
90 | }
91 |
92 | public function getModifiedBy(): ?User
93 | {
94 | return $this->modifiedBy;
95 | }
96 |
97 | public function setCreated(DateTime $created): void
98 | {
99 | $this->created = $created;
100 | }
101 |
102 | public function getCreated(): DateTime
103 | {
104 | return $this->created;
105 | }
106 |
107 | public function setModified(DateTime $modified): void
108 | {
109 | $this->modified = $modified;
110 | }
111 |
112 | public function getModified(): ?DateTime
113 | {
114 | return $this->modified;
115 | }
116 |
117 | /**
118 | * @PrePersist
119 | */
120 | public function prePersist(LifecycleEventArgs $eventArgs): void
121 | {
122 | $this->setCreated(new DateTime('now'));
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/src/Entity/DatascribeRecord.php:
--------------------------------------------------------------------------------
1 | values = new ArrayCollection;
70 | }
71 |
72 | public function setItem(DatascribeItem $item): void
73 | {
74 | $this->item = $item;
75 | }
76 |
77 | public function getItem(): DatascribeItem
78 | {
79 | return $this->item;
80 | }
81 |
82 | public function setNeedsReview(bool $needsReview): void
83 | {
84 | $this->needsReview = $needsReview;
85 | }
86 |
87 | public function getNeedsReview(): bool
88 | {
89 | return $this->needsReview;
90 | }
91 |
92 | public function setNeedsWork(bool $needsWork): void
93 | {
94 | $this->needsWork = $needsWork;
95 | }
96 |
97 | public function getNeedsWork(): bool
98 | {
99 | return $this->needsWork;
100 | }
101 |
102 | public function setPosition(int $position): void
103 | {
104 | $this->position = $position;
105 | }
106 |
107 | public function getPosition(): int
108 | {
109 | return $this->position;
110 | }
111 |
112 | public function setPositionChange(string $direction, int $recordId): void
113 | {
114 | if (!in_array($direction, ['before', 'after'])) {
115 | $direction = 'before'; // default direction is "above"
116 | }
117 | $this->positionChange = [
118 | 'direction' => $direction,
119 | 'record_id' => $recordId,
120 | ];
121 | }
122 |
123 | public function getPositionChange(): ?array
124 | {
125 | return $this->positionChange;
126 | }
127 |
128 | public function getValues()
129 | {
130 | return $this->values;
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/view/datascribe/admin/item/show-details.phtml:
--------------------------------------------------------------------------------
1 | translate('Item metadata'); ?>
2 |
6 |
10 |
14 |
18 |
22 |
26 |
30 |
47 |
64 |
81 |
85 |
89 |
--------------------------------------------------------------------------------
/view/datascribe/admin/record/media-viewer.phtml:
--------------------------------------------------------------------------------
1 | headScript()->appendFile($this->assetUrl('vendor/openseadragon/openseadragon.min.js', 'Omeka'));
3 | $this->headScript()->appendFile($this->assetUrl('vendor/panzoom-4.3.1/dist/panzoom.min.js', 'Datascribe'));
4 | $this->headScript()->appendFile($this->assetUrl('js/admin/media-viewer.js', 'Datascribe'));
5 | $allowedMediaTypes = ['image/bmp', 'image/gif', 'image/jpeg', 'image/png', 'image/svg+xml'];
6 | $medias = [];
7 | foreach ($oItem->media() as $media) {
8 | if (in_array($media->mediaType(), $allowedMediaTypes) || 'iiif' === $media->renderer()) {
9 | $medias[$media->id()] = $media;
10 | }
11 | }
12 | $mediaCount = count($medias);
13 | $mediaPage = 1;
14 | ?>
15 |
51 |
--------------------------------------------------------------------------------
/src/ControllerPlugin/Datascribe.php:
--------------------------------------------------------------------------------
1 | services = $services;
24 | }
25 |
26 | /**
27 | * Get a DataScribe representation.
28 | *
29 | * Provides a single method to get a DataScribe project, dataset, item, or
30 | * record representation. Used primarily to ensure that the route is valid.
31 | *
32 | * @param int $projectId
33 | * @param int|null $datasetId
34 | * @param int|null $itemId
35 | * @return DatascribeProjectRepresentation|DatascribeDatasetRepresentation|DatascribeItemRepresentation|DatascribeRecordRepresentation
36 | */
37 | public function getRepresentation(int $projectId, ?int $datasetId = null, ?int $itemId = null, ?int $recordId = null)
38 | {
39 | $controller = $this->getController();
40 | if ($recordId) {
41 | try {
42 | $record = $controller->api()->read('datascribe_records', $recordId)->getContent();
43 | } catch (NotFoundException $e) {
44 | return false;
45 | }
46 | $item = $record->item();
47 | $dataset = $item->dataset();
48 | $project = $dataset->project();
49 | return (($itemId === $item->id()) && ($datasetId === $dataset->id()) && ($projectId === $project->id()))
50 | ? $record : false;
51 | }
52 | if ($itemId) {
53 | try {
54 | $item = $controller->api()->read('datascribe_items', $itemId)->getContent();
55 | } catch (NotFoundException $e) {
56 | return false;
57 | }
58 | $dataset = $item->dataset();
59 | $project = $dataset->project();
60 | return (($datasetId === $dataset->id()) && ($projectId === $project->id()))
61 | ? $item : false;
62 | }
63 | if ($datasetId) {
64 | try {
65 | $dataset = $controller->api()->read('datascribe_datasets', $datasetId)->getContent();
66 | } catch (NotFoundException $e) {
67 | return false;
68 | }
69 | $project = $dataset->project();
70 | return ($projectId === $project->id())
71 | ? $dataset : false;
72 | }
73 | try {
74 | $project = $controller->api()->read('datascribe_projects', $projectId)->getContent();
75 | } catch (NotFoundException $e) {
76 | return false;
77 | }
78 | return $project;
79 | }
80 |
81 | /**
82 | * Revert the DataScribe item's review status to "not reviewed".
83 | *
84 | * @param int $itemId The DataScribe item ID
85 | */
86 | public function revertReviewStatus($itemId)
87 | {
88 | $em = $this->services->get('Omeka\EntityManager');
89 | $itemEntity = $em->find('Datascribe\Entity\DatascribeItem', $itemId);
90 | $itemEntity->setReviewed(null);
91 | $itemEntity->setReviewedBy(null);
92 | $itemEntity->setIsApproved(null);
93 | $em->flush();
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/view/datascribe/admin/project/browse.phtml:
--------------------------------------------------------------------------------
1 | htmlElement('body')->appendAttribute('class', 'datascribe project browse');
3 | ?>
4 |
5 | pageTitle($this->translate('Projects'), 1, $this->translate('DataScribe')); ?>
6 |
7 | userIsAllowed('Datascribe\Api\Adapter\DatascribeProjectAdapter', 'create')): ?>
8 |
9 |
12 |
13 |
14 |
15 | datascribe()->breadcrumbs(); ?>
16 |
17 |
18 | pagination(); ?>
19 | sortSelector([
20 | [
21 | 'label' => $this->translate('Date created'),
22 | 'value' => 'created',
23 | ],
24 | [
25 | 'label' => $this->translate('Name'),
26 | 'value' => 'name',
27 | ],
28 | ]); ?>
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | | translate('Project'); ?> |
37 | translate('Created by'); ?> |
38 | translate('Created'); ?> |
39 |
40 |
41 |
42 |
43 | createdBy(); ?>
44 |
45 |
46 | link($project->name()); ?>
47 | isPublic()): ?>
48 |
49 |
50 |
51 | userIsAllowed('update')): ?>
52 | - link('', 'edit', [
53 | 'class' => 'o-icon-edit',
54 | 'title' => $this->translate('Edit'),
55 | ]) ?>
56 |
57 | - hyperlink('', '#', [
58 | 'data-sidebar-content-url' => $project->url('show-details'),
59 | 'class' => 'o-icon-more sidebar-content',
60 | 'data-sidebar-selector' => '#show-details',
61 | 'title' => $this->translate('Details'),
62 | ]); ?>
63 |
64 | |
65 | link($createdBy->name()) : ''; ?> |
66 | i18n()->dateFormat($project->created()); ?> |
67 |
68 |
69 |
70 |
71 |
72 |
73 | pagination(); ?>
74 |
75 |
76 |
83 |
84 |
85 |
86 | userIsAllowed('Datascribe\Api\Adapter\DatascribeProjectAdapter', 'create')): ?>
87 |
translate('No projects found. %s'),
89 | $this->hyperlink($this->translate('Add a new project.'), $this->url('admin/datascribe-project', ['action' => 'add']))
90 | ); ?>
91 |
92 |
translate('No projects found.'); ?>
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/src/DatascribeDataType/Time.php:
--------------------------------------------------------------------------------
1 | addTimeFieldElements($fieldset, $fieldData);
17 | }
18 |
19 | public function getFieldDataFromUserData(array $userData): array
20 | {
21 | return $this->getTimeFieldDataFromUserData($userData);
22 | }
23 |
24 | public function addValueElements(Fieldset $fieldset, array $fieldData, ?string $valueText): void
25 | {
26 | $array = $this->getTimeArray($valueText);
27 | $this->addTimeValueElements($fieldset, $fieldData, $valueText, $array);
28 | }
29 |
30 | public function getValueTextFromUserData(array $userData): ?string
31 | {
32 | $array = [
33 | 'hour' => $userData['hour'] ?? null,
34 | 'minute' => $userData['minute'] ?? null,
35 | 'second' => $userData['second'] ?? null,
36 | ];
37 | return $this->getTimeString($this->emptyValuesToNull($array));
38 | }
39 |
40 | public function valueTextIsValid(array $fieldData, ?string $valueText): bool
41 | {
42 | $array = $this->getTimeArray($valueText);
43 |
44 | $hourSelect = new DatascribeElement\HourSelect('hour', ['datascribe_field_data' => $fieldData]);
45 | $minuteSelect = new DatascribeElement\MinuteSelect('minute', ['datascribe_field_data' => $fieldData]);
46 | $secondSelect = new DatascribeElement\SecondSelect('second', ['datascribe_field_data' => $fieldData]);
47 |
48 | if (is_numeric($array['second'])) {
49 | return (
50 | $this->isValid($hourSelect, $array['hour'])
51 | && $this->isValid($minuteSelect, $array['minute'])
52 | && $this->isValid($secondSelect, $array['second'])
53 | );
54 | }
55 | if (is_numeric($array['minute'])) {
56 | return (
57 | $this->isValid($hourSelect, $array['hour'])
58 | && $this->isValid($minuteSelect, $array['minute'])
59 | );
60 | }
61 | if (is_numeric($array['hour'])) {
62 | return (
63 | $this->isValid($hourSelect, $array['hour'])
64 | );
65 | }
66 | return false;
67 | }
68 |
69 | /**
70 | * Get an array of time data given an ISO 8601 string.
71 | *
72 | * @param ?string $string
73 | * @return array
74 | */
75 | protected function getTimeArray(?string $string)
76 | {
77 | $regex = sprintf('^%s?$', self::REGEX_ISO8601_TIME);
78 | preg_match(sprintf('/%s/', $regex), (string) $string, $matches);
79 | return [
80 | 'hour' => isset($matches[1]) ? (int) $matches[1] : null,
81 | 'minute' => isset($matches[3]) ? (int) $matches[3] : null,
82 | 'second' => isset($matches[5]) ? (int) $matches[5] : null,
83 | ];
84 | }
85 |
86 | /**
87 | * Get an ISO 8601 string given an array of time data.
88 | *
89 | * @param array $array
90 | * @return ?string
91 | */
92 | protected function getTimeString(array $array): ?string
93 | {
94 | if (isset($array['hour']) && isset($array['minute']) && isset($array['second'])) {
95 | return sprintf('%02d:%02d:%02d', $array['hour'], $array['minute'], $array['second']);
96 | }
97 | if (isset($array['hour']) && isset($array['minute'])) {
98 | return sprintf('%02d:%02d', $array['hour'], $array['minute']);
99 | }
100 | if (isset($array['hour'])) {
101 | return sprintf('%02d', $array['hour']);
102 | }
103 | return null;
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/src/DatascribeDataType/Checkbox.php:
--------------------------------------------------------------------------------
1 | setLabel('Checkbox label'); // @translate
22 | $element->setAttribute('value', $fieldData['label'] ?? null);
23 | $fieldset->add($element);
24 |
25 | $element = new Element\Text('checked_value');
26 | $element->setLabel('Checked value'); // @translate
27 | $element->setAttribute('value', $fieldData['checked_value'] ?? self::DEFAULT_CHECKED_VALUE);
28 | $fieldset->add($element);
29 |
30 | $element = new Element\Text('unchecked_value');
31 | $element->setLabel('Unhecked value'); // @translate
32 | $element->setAttribute('value', $fieldData['unchecked_value'] ?? self::DEFAULT_UNCHECKED_VALUE);
33 | $fieldset->add($element);
34 |
35 | $element = new DatascribeElement\OptionalCheckbox('checked_by_default');
36 | $element->setLabel('Checked by default'); // @translate
37 | $element->setValue($fieldData['checked_by_default'] ?? '0');
38 | $fieldset->add($element);
39 | }
40 |
41 | public function getFieldDataFromUserData(array $userData): array
42 | {
43 | $fieldData = [];
44 | $fieldData['checked_value'] =
45 | (isset($userData['checked_value']) && preg_match('/^.+$/', $userData['checked_value']))
46 | ? $userData['checked_value'] : self::DEFAULT_CHECKED_VALUE;
47 | $fieldData['unchecked_value'] =
48 | (isset($userData['unchecked_value']) && preg_match('/^.+$/', $userData['unchecked_value']))
49 | ? $userData['unchecked_value'] : self::DEFAULT_UNCHECKED_VALUE;
50 | $fieldData['checked_by_default'] =
51 | (isset($userData['checked_by_default']) && in_array($userData['checked_by_default'], ['0', '1']))
52 | ? $userData['checked_by_default'] : '0';
53 | $fieldData['label'] =
54 | (isset($userData['label']) && preg_match('/^.+$/', $userData['label']))
55 | ? $userData['label'] : null;
56 | return $fieldData;
57 | }
58 |
59 | public function fieldDataIsValid(array $fieldData): bool
60 | {
61 | if ($fieldData['checked_value'] === $fieldData['unchecked_value']) {
62 | return false;
63 | }
64 | return true;
65 | }
66 |
67 | public function addValueElements(Fieldset $fieldset, array $fieldData, ?string $valueText): void
68 | {
69 | $element = new DatascribeElement\OptionalCheckbox('value');
70 | $element->setLabel($fieldData['label'] ?? 'Check'); // @translate
71 | $element->setUseHiddenElement(true);
72 | $element->setCheckedValue($fieldData['checked_value'] ?? self::DEFAULT_CHECKED_VALUE);
73 | $element->setUncheckedValue($fieldData['unchecked_value'] ?? self::DEFAULT_UNCHECKED_VALUE);
74 | if (is_null($valueText) && isset($fieldData['checked_by_default']) && '1' === $fieldData['checked_by_default']) {
75 | $valueText = $fieldData['checked_value'] ?? self::DEFAULT_CHECKED_VALUE;
76 | }
77 | $element->setValue($valueText);
78 | $fieldset->add($element);
79 | }
80 |
81 | public function getValueTextFromUserData(array $userData): ?string
82 | {
83 | return $userData['value'] ?? null;
84 | }
85 |
86 | public function valueTextIsValid(array $fieldData, ?string $valueText): bool
87 | {
88 | $checkedValue = $fieldData['checked_value'] ?? self::DEFAULT_CHECKED_VALUE;
89 | $uncheckedValue = $fieldData['unchecked_value'] ?? self::DEFAULT_UNCHECKED_VALUE;
90 | return in_array($valueText, [$checkedValue, $uncheckedValue]);
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/DatascribeDataType/Date.php:
--------------------------------------------------------------------------------
1 | addDateFieldElements($fieldset, $fieldData);
17 | }
18 |
19 | public function getFieldDataFromUserData(array $userData): array
20 | {
21 | return $this->getDateFieldDataFromUserData($userData);
22 | }
23 |
24 | public function addValueElements(Fieldset $fieldset, array $fieldData, ?string $valueText): void
25 | {
26 | $array = $this->getDateArray($valueText);
27 | $this->addDateValueElements($fieldset, $fieldData, $valueText, $array);
28 | }
29 |
30 | public function getValueTextFromUserData(array $userData): ?string
31 | {
32 | $array = [
33 | 'year' => $userData['year'] ?? null,
34 | 'month' => $userData['month'] ?? null,
35 | 'day' => $userData['day'] ?? null,
36 | ];
37 | return $this->getDateString($this->emptyValuesToNull($array));
38 | }
39 |
40 | public function valueTextIsValid(array $fieldData, ?string $valueText): bool
41 | {
42 | $array = $this->getDateArray($valueText);
43 |
44 | $yearSelect = new DatascribeElement\YearSelect('year', ['datascribe_field_data' => $fieldData]);
45 | $monthSelect = new DatascribeElement\MonthSelect('month', ['datascribe_field_data' => $fieldData]);
46 | $daySelect = new DatascribeElement\DaySelect('day', ['datascribe_field_data' => $fieldData]);
47 |
48 | if (is_numeric($array['day'])) {
49 | return (
50 | $this->isValid($yearSelect, $array['year'])
51 | && $this->isValid($monthSelect, $array['month'])
52 | && $this->isValid($daySelect, $array['day'])
53 | );
54 | }
55 | if (is_numeric($array['month'])) {
56 | return (
57 | $this->isValid($yearSelect, $array['year'])
58 | && $this->isValid($monthSelect, $array['month'])
59 | );
60 | }
61 | if (is_numeric($array['year'])) {
62 | return (
63 | $this->isValid($yearSelect, $array['year'])
64 | );
65 | }
66 | return false;
67 | }
68 |
69 | /**
70 | * Get an array of date data given an ISO 8601 string.
71 | *
72 | * @param ?string $string
73 | * @return array
74 | */
75 | protected function getDateArray(?string $string)
76 | {
77 | $regex = sprintf('^%s?$', self::REGEX_ISO8601_DATE);
78 | preg_match(sprintf('/%s/', $regex), (string) $string, $matches);
79 | $year = sprintf('%s%s', $matches[1] ?? '', $matches[2] ?? '');
80 | return [
81 | 'year' => $year ? (int) $year : null,
82 | 'month' => isset($matches[4]) ? (int) $matches[4] : null,
83 | 'day' => isset($matches[6]) ? (int) $matches[6] : null,
84 | ];
85 | }
86 |
87 | /**
88 | * Get an ISO 8601 string given an array of date data.
89 | *
90 | * @param array $array
91 | * @return ?string
92 | */
93 | protected function getDateString(array $array): ?string
94 | {
95 | if (isset($array['year'])) {
96 | preg_match('/^(-)?(\d+)$/', $array['year'], $matches);
97 | $year = [$matches[1] ?? null, $matches[2]];
98 | }
99 | if (isset($array['year']) && isset($array['month']) && isset($array['day'])) {
100 | return sprintf('%s%04d-%02d-%02d', $year[0], $year[1], $array['month'], $array['day']);
101 | }
102 | if (isset($array['year']) && isset($array['month'])) {
103 | return sprintf('%s%04d-%02d', $year[0], $year[1], $array['month']);
104 | }
105 | if (isset($array['year'])) {
106 | return sprintf('%s%04d', $year[0], $year[1]);
107 | }
108 | return null;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/Api/Representation/DatascribeValueRepresentation.php:
--------------------------------------------------------------------------------
1 | setServiceLocator($services);
22 | $this->value = $value;
23 | }
24 |
25 | public function jsonSerialize(): array
26 | {
27 | }
28 |
29 | public function id()
30 | {
31 | return $this->value->getId();
32 | }
33 |
34 | public function field()
35 | {
36 | return new DatascribeFieldRepresentation(
37 | $this->value->getField(),
38 | $this->getServiceLocator()
39 | );
40 | }
41 |
42 | public function record()
43 | {
44 | return $this->getAdapter('datascribe_records')
45 | ->getRepresentation($this->value->getRecord());
46 | }
47 |
48 | public function isInvalid()
49 | {
50 | return $this->value->getIsInvalid();
51 | }
52 |
53 | public function isMissing()
54 | {
55 | return $this->value->getIsMissing();
56 | }
57 |
58 | public function isIllegible()
59 | {
60 | return $this->value->getIsIllegible();
61 | }
62 |
63 | public function text()
64 | {
65 | return $this->value->getText();
66 | }
67 |
68 | public function textIsValid()
69 | {
70 | $text = $this->text();
71 | $field = $this->field();
72 | if (null === $text) {
73 | // Null text is invalid if the field is required and the value is
74 | // not missing and not illegible.
75 | return !($field->isRequired() && !$this->isMissing() && !$this->isIllegible());
76 | }
77 | return $field->dataTypeService()->valueTextIsValid($field->data(), $text);
78 | }
79 |
80 | /**
81 | * Return this value's text formatted for display.
82 | *
83 | * The options are:
84 | * - length: the maximum length of the text (default is null)
85 | * - trim_marker: a string that follows text that exceeds the maximum length (defualt is null)
86 | * - if_unknown_return: return this if the text is unknown (default is false)
87 | * - if_invalid_return: return this if the text is invalid (default is false)
88 | * - if_null_return: return this if the text is null (default is null)
89 | * - if_empty_return: return this if the text is empty (default is an empty string)
90 | *
91 | * @param array $options
92 | * @return mixed
93 | */
94 | public function displayText(array $options = [])
95 | {
96 | // Set default options.
97 | $options['length'] ??= null;
98 | $options['trim_marker'] ??= null;
99 | $options['if_unknown_return'] ??= false;
100 | $options['if_invalid_return'] ??= false;
101 | $options['if_null_return'] ??= null;
102 | $options['if_empty_return'] ??= '';
103 |
104 | if ($this->field()->dataTypeIsUnknown()) {
105 | return $options['if_unknown_return'];
106 | }
107 | if (!$this->textIsValid()) {
108 | return $options['if_invalid_return'];
109 | }
110 | if (null === $this->text()) {
111 | return $options['if_null_return'];
112 | }
113 | $text = $this->text();
114 | $textLength = mb_strlen($text);
115 | if (0 === $textLength) {
116 | return $options['if_empty_return'];
117 | }
118 | if ($options['length']) {
119 | $text = mb_substr($text, 0, (int) $options['length']);
120 | }
121 | if ($options['trim_marker'] && $textLength > mb_strlen($text)) {
122 | $text .= $options['trim_marker'];
123 | }
124 | return $text;
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/asset/vendor/panzoom-4.3.1/src/css.ts:
--------------------------------------------------------------------------------
1 | import { CurrentValues, PanzoomOptions } from './types'
2 |
3 | const isIE = typeof document !== 'undefined' && !!(document as any).documentMode
4 |
5 | /**
6 | * Lazy creation of a CSS style declaration
7 | */
8 | let divStyle: CSSStyleDeclaration
9 | function createStyle() {
10 | if (divStyle) {
11 | return divStyle
12 | }
13 | return (divStyle = document.createElement('div').style)
14 | }
15 |
16 | /**
17 | * Proper prefixing for cross-browser compatibility
18 | */
19 | const prefixes = ['webkit', 'moz', 'ms']
20 | const prefixCache: { [key: string]: string } = {}
21 | function getPrefixedName(name: string) {
22 | if (prefixCache[name]) {
23 | return prefixCache[name]
24 | }
25 | const divStyle = createStyle()
26 | if (name in divStyle) {
27 | return (prefixCache[name] = name)
28 | }
29 | const capName = name[0].toUpperCase() + name.slice(1)
30 | let i = prefixes.length
31 | while (i--) {
32 | const prefixedName = `${prefixes[i]}${capName}`
33 | if (prefixedName in divStyle) {
34 | return (prefixCache[name] = prefixedName)
35 | }
36 | }
37 | }
38 |
39 | /**
40 | * Gets a style value expected to be a number
41 | */
42 | export function getCSSNum(name: string, style: CSSStyleDeclaration) {
43 | return parseFloat(style[getPrefixedName(name) as any]) || 0
44 | }
45 |
46 | function getBoxStyle(
47 | elem: HTMLElement | SVGElement,
48 | name: string,
49 | style: CSSStyleDeclaration = window.getComputedStyle(elem)
50 | ) {
51 | // Support: FF 68+
52 | // Firefox requires specificity for border
53 | const suffix = name === 'border' ? 'Width' : ''
54 | return {
55 | left: getCSSNum(`${name}Left${suffix}`, style),
56 | right: getCSSNum(`${name}Right${suffix}`, style),
57 | top: getCSSNum(`${name}Top${suffix}`, style),
58 | bottom: getCSSNum(`${name}Bottom${suffix}`, style)
59 | }
60 | }
61 |
62 | /**
63 | * Set a style using the properly prefixed name
64 | */
65 | export function setStyle(elem: HTMLElement | SVGElement, name: string, value: string) {
66 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
67 | elem.style[getPrefixedName(name) as any] = value
68 | }
69 |
70 | /**
71 | * Constructs the transition from panzoom options
72 | * and takes care of prefixing the transition and transform
73 | */
74 | export function setTransition(elem: HTMLElement | SVGElement, options: PanzoomOptions) {
75 | const transform = getPrefixedName('transform')
76 | setStyle(elem, 'transition', `${transform} ${options.duration}ms ${options.easing}`)
77 | }
78 |
79 | /**
80 | * Set the transform using the proper prefix
81 | */
82 | export function setTransform(
83 | elem: HTMLElement | SVGElement,
84 | { x, y, scale, isSVG }: CurrentValues,
85 | _options?: PanzoomOptions
86 | ) {
87 | setStyle(elem, 'transform', `scale(${scale}) translate(${x}px, ${y}px)`)
88 | if (isSVG && isIE) {
89 | const matrixValue = window.getComputedStyle(elem).getPropertyValue('transform')
90 | elem.setAttribute('transform', matrixValue)
91 | }
92 | }
93 |
94 | /**
95 | * Dimensions used in containment and focal point zooming
96 | */
97 | export function getDimensions(elem: HTMLElement | SVGElement) {
98 | const parent = elem.parentNode as HTMLElement | SVGElement
99 | const style = window.getComputedStyle(elem)
100 | const parentStyle = window.getComputedStyle(parent)
101 | const rectElem = elem.getBoundingClientRect()
102 | const rectParent = parent.getBoundingClientRect()
103 |
104 | return {
105 | elem: {
106 | style,
107 | width: rectElem.width,
108 | height: rectElem.height,
109 | top: rectElem.top,
110 | bottom: rectElem.bottom,
111 | left: rectElem.left,
112 | right: rectElem.right,
113 | margin: getBoxStyle(elem, 'margin', style),
114 | border: getBoxStyle(elem, 'border', style)
115 | },
116 | parent: {
117 | style: parentStyle,
118 | width: rectParent.width,
119 | height: rectParent.height,
120 | top: rectParent.top,
121 | bottom: rectParent.bottom,
122 | left: rectParent.left,
123 | right: rectParent.right,
124 | padding: getBoxStyle(parent, 'padding', parentStyle),
125 | border: getBoxStyle(parent, 'border', parentStyle)
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/view/datascribe/admin/dataset/browse.phtml:
--------------------------------------------------------------------------------
1 | htmlElement('body')->appendAttribute('class', 'datascribe dataset browse');
3 | ?>
4 |
5 | pageTitle($project->name(), 1, $this->translate('DataScribe: Project'), $this->translate('Datasets')); ?>
6 |
7 | userIsAllowed('update')): ?>
8 |
9 | link($this->translate('Edit project'), 'edit', ['class' => 'button']); ?>
10 | hyperlink($this->translate('Add new dataset'), $this->url('admin/datascribe-dataset', ['action' => 'add', 'project-id' => $project->id()]), ['class' => 'button']); ?>
11 |
12 |
13 |
14 | datascribe()->breadcrumbs(); ?>
15 |
16 |
17 | pagination(); ?>
18 | sortSelector([
19 | [
20 | 'label' => $this->translate('Date created'),
21 | 'value' => 'created',
22 | ],
23 | [
24 | 'label' => $this->translate('Name'),
25 | 'value' => 'name',
26 | ],
27 | ]); ?>
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | | translate('Dataset'); ?> |
36 | translate('Created by'); ?> |
37 | translate('Created'); ?> |
38 |
39 |
40 |
41 |
42 | createdBy();
44 | $modified = $dataset->modified();
45 | $modifiedBy = $dataset->modifiedBy();
46 | ?>
47 |
48 |
49 | link($dataset->name()); ?>
50 | isPublic()): ?>
51 |
52 |
53 |
54 | userIsAllowed('update')): ?>
55 | - link('', 'edit', [
56 | 'class' => 'o-icon-edit',
57 | 'title' => $this->translate('Edit'),
58 | ]) ?>
59 |
60 | - hyperlink('', '#', [
61 | 'data-sidebar-content-url' => $dataset->url('show-details'),
62 | 'class' => 'o-icon-more sidebar-content',
63 | 'data-sidebar-selector' => '#show-details',
64 | 'title' => $this->translate('Details'),
65 | ]); ?>
66 |
67 | |
68 | link($createdBy->name()) : ''; ?> |
69 | i18n()->dateFormat($dataset->created()); ?> |
70 |
71 |
72 |
73 |
74 |
75 |
76 | pagination(); ?>
77 |
78 |
79 |
80 |
81 | userIsAllowed('Datascribe\Api\Adapter\DatascribeDatasetAdapter', 'create')): ?>
82 |
translate('No datasets found for this project. %s'),
84 | $this->hyperlink($this->translate('Add a new dataset.'), $this->url('admin/datascribe-dataset', ['action' => 'add', 'project-id' => $project->id()]))
85 | ); ?>
86 |
87 |
translate('No datasets found for this project.'); ?>
88 |
89 |
90 |
91 |
92 |
96 |
97 |
104 |
--------------------------------------------------------------------------------
/src/Entity/DatascribeField.php:
--------------------------------------------------------------------------------
1 | values = new ArrayCollection;
101 | }
102 |
103 | public function setName(string $name): void
104 | {
105 | $this->name = $name;
106 | }
107 |
108 | public function getName(): string
109 | {
110 | return $this->name;
111 | }
112 |
113 | public function setDescription(?string $description): void
114 | {
115 | if (is_string($description) && '' === trim($description)) {
116 | $description = null;
117 | }
118 | $this->description = $description;
119 | }
120 |
121 | public function getDescription(): ?string
122 | {
123 | return $this->description;
124 | }
125 |
126 | public function setDataset(DatascribeDataset $dataset): void
127 | {
128 | $this->dataset = $dataset;
129 | }
130 |
131 | public function getDataset(): DatascribeDataset
132 | {
133 | return $this->dataset;
134 | }
135 |
136 | public function setPosition(int $position): void
137 | {
138 | $this->position = $position;
139 | }
140 |
141 | public function getPosition(): int
142 | {
143 | return $this->position;
144 | }
145 |
146 | public function setIsPrimary(bool $isPrimary): void
147 | {
148 | $this->isPrimary = $isPrimary;
149 | }
150 |
151 | public function getIsPrimary(): ?bool
152 | {
153 | return $this->isPrimary;
154 | }
155 |
156 | public function setIsRequired(bool $isRequired): void
157 | {
158 | $this->isRequired = $isRequired;
159 | }
160 |
161 | public function getIsRequired(): ?bool
162 | {
163 | return $this->isRequired;
164 | }
165 |
166 | public function setDataType(?string $dataType): void
167 | {
168 | $this->dataType = $dataType;
169 | }
170 |
171 | public function getDataType(): ?string
172 | {
173 | return $this->dataType;
174 | }
175 |
176 | public function setData(array $data): void
177 | {
178 | $this->data = $data;
179 | }
180 |
181 | public function getData(): array
182 | {
183 | return $this->data;
184 | }
185 |
186 | public function getValues()
187 | {
188 | return $this->values;
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/view/datascribe/admin/dataset/edit.phtml:
--------------------------------------------------------------------------------
1 | headScript()->appendFile($this->assetUrl('vendor/sortablejs/Sortable.min.js', 'Omeka'));
3 | $this->headScript()->appendFile($this->assetUrl('js/admin/dataset-form.js', 'Datascribe'));
4 | $this->ckEditor();
5 | $this->htmlElement('body')->appendAttribute('class', 'datascribe dataset edit');
6 | $form->prepare();
7 | ?>
8 |
9 | pageTitle($dataset->name(), 1, $this->translate('DataScribe: Dataset'), $this->translate('Edit')); ?>
10 |
11 | form()->openTag($form); ?>
12 | formElement($form->get('csrf')); ?>
13 |
14 |
15 | isPublic()): ?>
16 | hyperlink('', '#', [
17 | 'class' => 'o-icon-public button',
18 | 'title' => $this->translate('Make private'),
19 | ]); ?>
20 |
21 |
22 | hyperlink('', '#', [
23 | 'class' => 'o-icon-private button',
24 | 'title' => $this->translate('Make public'),
25 | ]); ?>
26 |
27 |
28 | hyperlink($this->translate('Cancel'), $this->url('admin/datascribe-item', ['action' => 'browse'], true), ['class' => 'button']); ?>
29 |
translate('Delete'); ?>
30 |
38 |
39 |
40 | sectionNav([
41 | 'general' => $this->translate('General'),
42 | 'form-builder' => $this->translate('Form Builder'),
43 | ]); ?>
44 |
45 |
46 | formRow($form->get('o-module-datascribe:name')); ?>
47 | formRow($form->get('o-module-datascribe:description')); ?>
48 | formRow($form->get('o-module-datascribe:guidelines')); ?>
49 | formRow($form->get('o:item_set')); ?>
50 | formRow($form->get('o-module-datascribe:revert_review_status')); ?>
51 | formRow($form->get('o-module-datascribe:export_missing_illegible')); ?>
52 |
53 |
54 |
71 |
72 |
73 | form()->closeTag(); ?>
74 |
75 | deleteConfirm($dataset, 'dataset'); ?>
76 |
77 | dataTypeTemplates();?>
78 |
--------------------------------------------------------------------------------
/src/Job/SyncDataset.php:
--------------------------------------------------------------------------------
1 | getArg('datascribe_dataset_id'))) {
22 | throw new Exception\RuntimeException('Missing datascribe_dataset_id');
23 | }
24 | $em = $this->getServiceLocator()->get('Omeka\EntityManager');
25 | $dataset = $em->find(DatascribeDataset::class, $this->getArg('datascribe_dataset_id'));
26 | if (null === $dataset) {
27 | throw new Exception\RuntimeException('Cannot find dataset');
28 | }
29 | if (null === $dataset->getItemSet()) {
30 | throw new Exception\RuntimeException('Cannot sync dataset without an item set');
31 | }
32 |
33 | $dataset->setSynced(new DateTime('now'));
34 | $dataset->setSyncedBy($this->job->getOwner());
35 |
36 | $dsItems = $this->getDatasetItemIds($dataset);
37 | $oItems = $this->getItemSetItemIds($dataset->getItemSet());
38 |
39 | // Calculate which items to delete and which to create.
40 | $toDelete = array_diff($dsItems, $oItems);
41 | $toCreate = array_diff($oItems, $dsItems);
42 |
43 | // Create new DataScribe items.
44 | foreach (array_chunk($toCreate, 100) as $toCreateChunk) {
45 | foreach ($toCreateChunk as $oItemId) {
46 | $dsItem = new DatascribeItem;
47 | $dsItem->setDataset($dataset);
48 | $dsItem->setItem($em->getReference(Item::class, $oItemId));
49 | $dsItem->setSynced(new DateTime('now'));
50 | $dsItem->setSyncedBy($this->job->getOwner());
51 | $em->persist($dsItem);
52 | }
53 | $em->flush();
54 | }
55 |
56 | // Delete removed DataScribe items.
57 | $query = $em->createQuery('
58 | DELETE FROM Datascribe\Entity\DatascribeItem dsitem
59 | WHERE dsitem.id IN (:dsitem_ids)
60 | ')->setParameter('dsitem_ids', array_keys($toDelete));
61 | $query->execute();
62 |
63 | $em->flush();
64 | }
65 |
66 | /**
67 | * Get the IDs of all items in the DataScribe dataset.
68 | *
69 | * @param DatascribeDataset $dataset
70 | * @return array
71 | */
72 | public function getDatasetItemIds(DatascribeDataset $dataset)
73 | {
74 | $em = $this->getServiceLocator()->get('Omeka\EntityManager');
75 | $query = $em->createQuery('
76 | SELECT dsitem.id dsitem_id, oitem.id oitem_id
77 | FROM Datascribe\Entity\DatascribeItem dsitem
78 | JOIN dsitem.item oitem
79 | JOIN dsitem.dataset dsdataset
80 | WHERE dsdataset.id = :dsdataset_id'
81 | );
82 | // Execute the statement directly to optimize memory usage.
83 | $conn = $em->getConnection();
84 | $stmt = $conn->prepare($query->getSQL());
85 | $stmt->bindValue(1, $dataset->getId());
86 | $stmt->execute();
87 | $results = [];
88 | foreach ($stmt as $row) {
89 | $results[$row['id_0']] = $row['id_1'];
90 | }
91 | return $results;
92 | }
93 |
94 | /**
95 | * Get the IDs of all items in the item set.
96 | *
97 | * @param ItemSet $itemSet
98 | * @return array
99 | */
100 | public function getItemSetItemIds(ItemSet $itemSet)
101 | {
102 | $em = $this->getServiceLocator()->get('Omeka\EntityManager');
103 | $query = $em->createQuery('
104 | SELECT item.id
105 | FROM Omeka\Entity\Item item
106 | JOIN item.itemSets item_set
107 | WHERE item_set.id = :item_set_id'
108 | );
109 | // Execute the statement directly to optimize memory usage.
110 | $conn = $em->getConnection();
111 | $stmt = $conn->prepare($query->getSQL());
112 | $stmt->bindValue(1, $itemSet->getId());
113 | $stmt->execute();
114 | $results = [];
115 | foreach ($stmt as $row) {
116 | $results[] = $row['id_0'];
117 | }
118 | return $results;
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/src/Form/ItemForm.php:
--------------------------------------------------------------------------------
1 | getOption('item');
11 | $project = $this->getOption('project');
12 |
13 | // transcriber_notes textarea
14 | if ($item->userIsAllowed('datascribe_edit_transcriber_notes')) {
15 | $element = new Element\Textarea('o-module-datascribe:transcriber_notes');
16 | $element->setValue($item->transcriberNotes());
17 | $this->add($element);
18 | }
19 |
20 | // reviewer_notes textarea
21 | if ($item->userIsAllowed('datascribe_edit_reviewer_notes')) {
22 | $element = new Element\Textarea('o-module-datascribe:reviewer_notes');
23 | $element->setValue($item->reviewerNotes());
24 | $this->add($element);
25 | }
26 |
27 | // submit_action select
28 | $element = new Element\Select('submit_action');
29 | $valueOptions = [
30 | '' => '[No change]', // @translate
31 | ];
32 | if ($item->userIsAllowed('datascribe_mark_item_submitted')) {
33 | $valueOptions['submitted'] = 'Submit for review'; // @translate
34 | }
35 | if ($item->userIsAllowed('datascribe_mark_item_not_submitted')) {
36 | $valueOptions['not_submitted'] = 'Mark as not submitted'; // @translate
37 | }
38 | $element->setValueOptions($valueOptions);
39 | $element->setAttribute('class', 'chosen-select');
40 | $this->add($element);
41 |
42 | // review_action select
43 | $element = new Element\Select('review_action');
44 | $valueOptions = [
45 | '' => '[No change]', // @translate
46 | ];
47 | if ($item->userIsAllowed('datascribe_mark_item_approved')) {
48 | $valueOptions['approved'] = 'Mark as approved'; // @translate
49 | }
50 | if ($item->userIsAllowed('datascribe_mark_item_not_approved')) {
51 | $valueOptions['not_approved'] = 'Mark as not approved'; // @translate
52 | }
53 | if ($item->userIsAllowed('datascribe_mark_item_not_reviewed')) {
54 | $valueOptions['not_reviewed'] = 'Mark as not reviewed'; // @translate
55 | }
56 | $element->setValueOptions($valueOptions);
57 | $element->setAttribute('class', 'chosen-select');
58 | $this->add($element);
59 |
60 | // lock_action select
61 | $element = new Element\Select('lock_action');
62 | $valueOptions = [
63 | '' => '[No change]', // @translate
64 | ];
65 | if ($item->userIsAllowed('datascribe_unlock_item')) {
66 | $valueOptions['unlock'] = 'Unlock'; // @translate
67 | }
68 | if ($item->userIsAllowed('datascribe_lock_item_to_self')) {
69 | $valueOptions['lock'] = 'Lock to me'; // @translate
70 | }
71 | if ($item->userIsAllowed('datascribe_lock_item_to_other')) {
72 | $valueOptions = $this->getLockToOtherValueOptions($valueOptions, $project);
73 | }
74 | $element->setValueOptions($valueOptions);
75 | $element->setAttribute('class', 'chosen-select');
76 | $this->add($element);
77 |
78 | // priority_action select
79 | $element = new Element\Select('priority_action');
80 | $valueOptions = [
81 | '' => '[No change]', // @translate
82 | ];
83 | if ($item->userIsAllowed('datascribe_mark_item_prioritized')) {
84 | $valueOptions['prioritized'] = 'Mark as prioritized'; // @translate
85 | }
86 | if ($item->userIsAllowed('datascribe_mark_item_not_prioritized')) {
87 | $valueOptions['not_prioritized'] = 'Mark as not prioritized'; // @translate
88 | }
89 | $element->setValueOptions($valueOptions);
90 | $element->setAttribute('class', 'chosen-select');
91 | $this->add($element);
92 |
93 | $inputFilter = $this->getInputFilter();
94 | $inputFilter->add([
95 | 'name' => 'submit_action',
96 | 'allow_empty' => true,
97 | ]);
98 | $inputFilter->add([
99 | 'name' => 'review_action',
100 | 'allow_empty' => true,
101 | ]);
102 | $inputFilter->add([
103 | 'name' => 'lock_action',
104 | 'allow_empty' => true,
105 | ]);
106 | $inputFilter->add([
107 | 'name' => 'priority_action',
108 | 'allow_empty' => true,
109 | ]);
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/Controller/Admin/ProjectController.php:
--------------------------------------------------------------------------------
1 | getForm(ProjectForm::class);
14 |
15 | if ($this->getRequest()->isPost()) {
16 | $form->setData($this->params()->fromPost());
17 | if ($form->isValid()) {
18 | $formData = $form->getData();
19 | $formData['o:is_public'] = $this->params()->fromPost('o:is_public');
20 | $formData['o-module-datascribe:user'] = $this->params()->fromPost('o-module-datascribe:user');
21 | $response = $this->api($form)->create('datascribe_projects', $formData);
22 | if ($response) {
23 | $this->messenger()->addSuccess('Project successfully created.'); // @translate
24 | return $this->redirect()->toUrl($response->getContent()->url());
25 | }
26 | } else {
27 | $this->messenger()->addFormErrors($form);
28 | }
29 | }
30 |
31 | $view = new ViewModel;
32 | $view->setVariable('form', $form);
33 | return $view;
34 | }
35 |
36 | public function editAction()
37 | {
38 | $project = $this->datascribe()->getRepresentation($this->params('project-id'));
39 | if (!$project) {
40 | return $this->redirect()->toRoute('admin/datascribe');
41 | }
42 | $form = $this->getForm(ProjectForm::class);
43 |
44 | if ($this->getRequest()->isPost()) {
45 | $form->setData($this->params()->fromPost());
46 | if ($form->isValid()) {
47 | $formData = $form->getData();
48 | $formData['o:is_public'] = $this->params()->fromPost('o:is_public');
49 | $formData['o-module-datascribe:user'] = $this->params()->fromPost('o-module-datascribe:user');
50 | $response = $this->api($form)->update('datascribe_projects', $this->params('project-id'), $formData);
51 | if ($response) {
52 | $this->messenger()->addSuccess('Project successfully edited.'); // @translate
53 | return $this->redirect()->toUrl($response->getContent()->url());
54 | }
55 | } else {
56 | $this->messenger()->addFormErrors($form);
57 | }
58 | } else {
59 | $data = $project->jsonSerialize();
60 | $form->setData($data);
61 | }
62 |
63 | $view = new ViewModel;
64 | $view->setVariable('form', $form);
65 | $view->setVariable('project', $project);
66 | return $view;
67 | }
68 |
69 | public function deleteAction()
70 | {
71 | if ($this->getRequest()->isPost()) {
72 | $form = $this->getForm(ConfirmForm::class);
73 | $form->setData($this->getRequest()->getPost());
74 | if ($form->isValid()) {
75 | $response = $this->api($form)->delete('datascribe_projects', $this->params('project-id'));
76 | if ($response) {
77 | $this->messenger()->addSuccess('Project successfully deleted'); // @translate
78 | }
79 | } else {
80 | $this->messenger()->addFormErrors($form);
81 | }
82 | }
83 | return $this->redirect()->toRoute(null, ['action' => 'browse'], true);
84 | }
85 |
86 | public function browseAction()
87 | {
88 | $this->setBrowseDefaults('created');
89 | $response = $this->api()->search('datascribe_projects', $this->params()->fromQuery());
90 | $this->paginator($response->getTotalResults(), $this->params()->fromQuery('page'));
91 | $projects = $response->getContent();
92 |
93 | $view = new ViewModel;
94 | $view->setVariable('projects', $projects);
95 | return $view;
96 | }
97 |
98 | public function showDetailsAction()
99 | {
100 | $project = $this->datascribe()->getRepresentation($this->params('project-id'));
101 | if (!$project) {
102 | exit;
103 | }
104 |
105 | $view = new ViewModel;
106 | $view->setTerminal(true);
107 | $view->setVariable('project', $project);
108 | return $view;
109 | }
110 |
111 | public function showAction()
112 | {
113 | return $this->redirect()->toRoute('admin/datascribe-dataset', ['action' => 'browse'], true);
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/Form/RecordBatchForm.php:
--------------------------------------------------------------------------------
1 | add([
11 | 'type' => 'select',
12 | 'name' => 'needs_review_action',
13 | 'options' => [
14 | 'label' => 'Needs review action', // @translate
15 | 'empty_option' => '',
16 | 'value_options' => [
17 | '1' => 'Mark as needs review', // @translate
18 | '0' => 'Mark as does not need review', // @translate
19 | ],
20 | ],
21 | 'attributes' => [
22 | 'class' => 'chosen-select',
23 | 'data-placeholder' => '[No change]', // @translate
24 | ],
25 | ]);
26 | $this->add([
27 | 'type' => 'select',
28 | 'name' => 'needs_work_action',
29 | 'options' => [
30 | 'label' => 'Needs work action', // @translate
31 | 'empty_option' => '',
32 | 'value_options' => [
33 | '1' => 'Mark as needs work', // @translate
34 | '0' => 'Mark as does not need work', // @translate
35 | ],
36 | ],
37 | 'attributes' => [
38 | 'class' => 'chosen-select',
39 | 'data-placeholder' => '[No change]', // @translate
40 | ],
41 | ]);
42 |
43 | $this->addValueElements();
44 |
45 | $inputFilter = $this->getInputFilter();
46 | $inputFilter->add([
47 | 'name' => 'needs_review_action',
48 | 'allow_empty' => true,
49 | ]);
50 | $inputFilter->add([
51 | 'name' => 'needs_work_action',
52 | 'allow_empty' => true,
53 | ]);
54 | }
55 |
56 | /**
57 | * Add all value elements configured for this dataset.
58 | */
59 | protected function addValueElements()
60 | {
61 | $dataset = $this->getOption('dataset');
62 |
63 | $valuesFieldset = new Fieldset('values');
64 | $this->add($valuesFieldset);
65 | foreach ($dataset->fields() as $field) {
66 | $valueFieldset = new Fieldset($field->id());
67 | $valueFieldset->setLabel($field->name());
68 | $valuesFieldset->add($valueFieldset);
69 | $valueFieldset->add([
70 | 'type' => 'select',
71 | 'name' => 'is_missing_action',
72 | 'options' => [
73 | 'label' => 'Is missing action', // @translate
74 | 'empty_option' => '',
75 | 'value_options' => [
76 | '1' => 'Mark as missing', // @translate
77 | '0' => 'Mark as not missing', // @translate
78 | ],
79 | ],
80 | 'attributes' => [
81 | 'class' => 'chosen-select',
82 | 'data-placeholder' => '[No change]', // @translate
83 | ],
84 | ]);
85 | $valueFieldset->add([
86 | 'type' => 'select',
87 | 'name' => 'is_illegible_action',
88 | 'options' => [
89 | 'label' => 'Is illegible action', // @translate
90 | 'empty_option' => '',
91 | 'value_options' => [
92 | '1' => 'Mark as illegible', // @translate
93 | '0' => 'Mark as not illegible', // @translate
94 | ],
95 | ],
96 | 'attributes' => [
97 | 'class' => 'chosen-select',
98 | 'data-placeholder' => '[No change]', // @translate
99 | ],
100 | ]);
101 | $valueFieldset->add([
102 | 'type' => 'checkbox',
103 | 'name' => 'edit_values',
104 | 'options' => [
105 | 'label' => 'Edit values?', // @transcribe
106 | ],
107 | ]);
108 | $valueDataFieldset = new Fieldset('data');
109 | $valueFieldset->add($valueDataFieldset);
110 | $field->dataTypeService()->addValueElements(
111 | $valueDataFieldset,
112 | $field->data(),
113 | null
114 | );
115 | }
116 |
117 | $inputFilter = $this->getInputFilter();
118 | $values = $inputFilter->get('values');
119 | foreach ($dataset->fields() as $field) {
120 | $value = $values->get($field->id());
121 | $value->add([
122 | 'name' => 'is_missing_action',
123 | 'allow_empty' => true,
124 | ]);
125 | $value->add([
126 | 'name' => 'is_illegible_action',
127 | 'allow_empty' => true,
128 | ]);
129 | }
130 | }
131 | }
132 |
--------------------------------------------------------------------------------