Commit f22a6227 authored by Romain Courteaud's avatar Romain Courteaud Committed by Gabriel Monnerat

erp5_document_scanner: Speed up the usability of scannerjs

- Stop relying of CSS hide/show attributes. Instead, only put needed elements in the DOM.

- Upload images asynchronously to improve the usability

Add a tales expression as default field value. The default value is a JSON containing 2 keys:
* the relative_url of an active process
* the list of active process image content to aggregate
By default, when the field is rendered for the first time, this tales expression is evaluated and a new active process is created at that point.
So, default json is like: {active_process: 'portal_activities/1234', image_list: []}
* store the active_process relative_url in the gadget state in the render method
* store the image_list in the gadget state in the render_method
* change getContent method to send a json build from the active_process and image_list state

- Change the gadget checkValidity method to return false when:
  * no thumbnail has been generated
  * a thumbnail upload is in failed state

- POST image cropped to backend
  * change the `extra renderjs` parameters list to pass a Python script to call when a new image is cropped.
  * change the gadget to use jio.util.ajax with the script full url (provided by the server)

- Translate and Update i18n info
- Ajax must return a active process image content UUID
- Add spinner in button to show that we are saving it in background
- Add reference to Active Process. With this, we can search easily active processes used by document scanner and remove them
- Add an alarm which will delete outdated (>5 days old) active_process created by the dialog.
- Improve code to switch cameras in mobiles with more than 2 cameras
- Display intermediate image after get orientation and instantiate Cropper
parent a24f56d6
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_view</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_view</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>document_scanner_preference</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>4.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Document Scanner</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/Preference_viewDocumentScannerSetting</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Alarm" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>active_sense_method_id</string> </key>
<value> <string>Alarm_removeOutdatedActiveProcess</string> </value>
</item>
<item>
<key> <string>automatic_solve</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>remove_outdated_document_scanner_active_processes</string> </value>
</item>
<item>
<key> <string>periodicity_day_frequency</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>periodicity_hour</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>periodicity_minute</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>periodicity_month</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>periodicity_month_day</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>periodicity_start_date</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1167609600.0</float>
<string>GMT</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>periodicity_week</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Alarm</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Remove Outdated Document Scanner Active Processes</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
.device-selector { div[data-gadget-url$="gadget_document_scanner.html"] {
text-align: center; text-align: center;
font-size: 19px;
} }
div[data-gadget-scope="field_your_document_scanner_gadget"] { @media only screen and (max-width: 750px) {
text-align: center; div[data-gadget-url$="gadget_document_scanner.html"] .camera {
max-width: 90%;
}
div[data-gadget-url$="gadget_document_scanner.html"] .thumbnail-list > button {
max-width: 50%;
}
} }
.video, .photo, .camera-output { div[data-gadget-url$="gadget_document_scanner.html"] .photo,
div[data-gadget-url$="gadget_document_scanner.html"] .video,
div[data-gadget-url$="gadget_document_scanner.html"] .camera-output,
div[data-gadget-url$="gadget_document_scanner.html"] .canvas {
max-width: 100%; max-width: 100%;
width: auto; width: auto;
max-height: 500px; max-height: 500px;
...@@ -15,69 +22,110 @@ div[data-gadget-scope="field_your_document_scanner_gadget"] { ...@@ -15,69 +22,110 @@ div[data-gadget-scope="field_your_document_scanner_gadget"] {
text-align: center; text-align: center;
} }
.camera-input, .camera-output { div[data-gadget-url$="gadget_document_scanner.html"] .camera-input {
min-height: 360px; min-height: 360px;
display: none;
} }
.canvas { div[data-gadget-url$="gadget_document_scanner.html"] .page-number {
display: none;
filter: brightness(1);
}
.page-number {
display: inline; display: inline;
} }
.camera-header { div[data-gadget-url$="gadget_document_scanner.html"] .camera-header {
font-size: 12pt; font-size: 12pt;
font-weight: 400; font-weight: 400;
} }
.camera-input, .camera-output, .camera-header, .edit-picture { div[data-gadget-url$="gadget_document_scanner.html"] .camera-input,
div[data-gadget-url$="gadget_document_scanner.html"] .camera-output,
div[data-gadget-url$="gadget_document_scanner.html"] .camera-header,
div[data-gadget-url$="gadget_document_scanner.html"] .edit-picture {
text-align: center; text-align: center;
} }
.camera, .camera-input, .camera-output { div[data-gadget-url$="gadget_document_scanner.html"] .edit-picture {
padding-top: 0.5em;
}
div[data-gadget-url$="gadget_document_scanner.html"] .camera,
div[data-gadget-url$="gadget_document_scanner.html"] .camera-input {
display: inline-block; display: inline-block;
} }
.capture-button, .reset-button { div[data-gadget-url$="gadget_document_scanner.html"] .reset-btn,
display: inline; div[data-gadget-url$="gadget_document_scanner.html"] .confirm-btn,
margin: 0 2em 0 2em; div[data-gadget-url$="gadget_document_scanner.html"] .edit-btn,
div[data-gadget-url$="gadget_document_scanner.html"] .take-picture-btn,
div[data-gadget-url$="gadget_document_scanner.html"] .capture-btn,
div[data-gadget-url$="gadget_document_scanner.html"] .delete-btn,
div[data-gadget-url$="gadget_document_scanner.html"] .retry-btn,
div[data-gadget-url$="gadget_document_scanner.html"] .change-camera-btn,
div[data-gadget-url$="gadget_document_scanner.html"] .confirm-btn {
color: #212529;
padding: 3pt;
border: 1px solid rgba(0, 0, 0, 0.14);
border-radius: 0.325em;
display: inline-block;
margin-right: 6pt;
} }
.startbutton { div[data-gadget-url$="gadget_document_scanner.html"] button:disabled,
display: block; div[data-gadget-url$="gadget_document_scanner.html"] button[disabled] {
margin: 0 auto; color: #999999;
} }
.reset-btn, .confirm-btn, .edit-btn, .take-picture-btn, div[data-gadget-url$="gadget_document_scanner.html"] > .camera > .thumbnail-list {
.capture-btn, .change-camera-btn, .confirm-btn { padding-top: .5em;
color: #212529; }
padding: 3pt;
div[data-gadget-url$="gadget_document_scanner.html"] .show-img {
width: 6em;
height: 6em;
object-fit: cover;
float: left;
}
div[data-gadget-url$="gadget_document_scanner.html"] .show-img ,
div[data-gadget-url$="gadget_document_scanner.html"] .new-btn {
border-radius: 0.325em;
}
div[data-gadget-url$="gadget_document_scanner.html"] .btn-thumbnail ,
div[data-gadget-url$="gadget_document_scanner.html"] .new-btn {
margin-top: 0.2em;
}
div[data-gadget-url$="gadget_document_scanner.html"] button:before {
padding-right: 0.2em;
}
div[data-gadget-url$="gadget_document_scanner.html"] .thumbnail-list > button {
display: inline;
float: left;
margin-left: 0.2em;
border: 1px solid rgba(0, 0, 0, 0.14); border: 1px solid rgba(0, 0, 0, 0.14);
border-radius: 0.325em; border-radius: 0.325em;
} }
.take-picture-btn, .capture-btn, .confirm-btn, div[data-gadget-url$="gadget_document_scanner.html"] .upload-error {
.reset-btn, .confirm-btn, .change-camera-btn, .edit-btn { border: 3px solid red;
display: none;
} }
.contentarea { div[data-gadget-url$="gadget_document_scanner.html"] .new-btn {
font-size: 16px; display: inline-grid !important;
font-family: "Lucida Grande", "Arial", sans-serif; width: calc(6em + 1px);
width: 760px; height: calc(6em + 1px);
} }
button:disabled, div[data-gadget-url$="gadget_document_scanner.html"] .img-container {
button[disabled]{ /* Never limit the container height here */
color: #999999; max-width: 100%;
} }
@media only screen and (max-width: 600px) { div[data-gadget-url$="gadget_document_scanner.html"] .btn-thumbnail:before {
body { color: #000;
max-height: 360px; position: absolute;
} transform: translate(-50%, -50%);
} -ms-transform: translate(-50%, -50%);
\ No newline at end of file text-align: center;
font-size: 16pt;
}
...@@ -3,10 +3,13 @@ ...@@ -3,10 +3,13 @@
<head> <head>
<!-- <!--
data-i18n=Webcam is not available data-i18n=Webcam is not available
data-i18n=Reset data-i18n=Delete
data-i18n=Take Picture data-i18n=Save
data-i18n=Confirm data-i18n=Capture
data-i18n=Edit data-i18n=Saving
data-i18n=Error
data-i18n=Page
data-i18n=New Page
data-i18n=Change Camera data-i18n=Change Camera
--> -->
<meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
...@@ -14,30 +17,12 @@ ...@@ -14,30 +17,12 @@
<link rel="stylesheet" href="gadget_document_scanner.css"> <link rel="stylesheet" href="gadget_document_scanner.css">
<link rel="stylesheet" href="cropper.min.css"> <link rel="stylesheet" href="cropper.min.css">
<script type="text/javascript" src="cropper.min.js"></script> <script type="text/javascript" src="cropper.min.js"></script>
<script type="text/javascript" src="domsugar.js"></script>
<script type="text/javascript" src="caman.full.min.js"></script>
<script type="text/javascript" src="gadget_document_scanner.js"></script> <script type="text/javascript" src="gadget_document_scanner.js"></script>
<title>Gadget Document Scanner</title> <title>Gadget Document Scanner</title>
</head> </head>
<body> <body>
<div class="camera"> <div></div>
<div class="camera-header">
<h4>Page <label class="page-number">1</label></h4>
</div>
<div class="camera-input">
<video class="video">Webcam is not available</video>
</div>
<canvas class="canvas"></canvas>
<div class="camera-output">
<img class="photo" alt="Photo">
<input class="photoInput" type="hidden">
<input type="hidden" name="page-number" value="1">
</div>
<div class="edit-picture">
<button type="button" class="reset-btn ui-btn-icon-left ui-icon-times"> Reset</button>
<button type="button" class="take-picture-btn ui-btn-icon-left ui-icon-circle"> Take Picture</button>
<button type="button" class="confirm-btn ui-btn-icon-left ui-icon-check"> Confirm</button>
<button type="button" class="edit-btn ui-btn-icon-left ui-icon-pencil"> Edit</button>
<button type="button" class="change-camera-btn ui-icon-refresh ui-btn-icon-left"> Change Camera</button>
</div>
</div>
</body> </body>
</html> </html>
\ No newline at end of file
<property_sheet_list>
<portal_type id="Active Process">
<item>Reference</item>
</portal_type>
</property_sheet_list>
\ No newline at end of file
assert context.getPortalType() == "Active Process", "It must be an Active Process"
assert context.getReference() == context.Base_getDocumentScannerDefaultReference(), "Unexpected reference"
context.getPortalObject().portal_activities.manage_delObjects(
ids=[context.getId(),])
...@@ -50,11 +50,11 @@ ...@@ -50,11 +50,11 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>classification=None, synchronous_metadata_discovery=None, cancel_url=None, batch_mode=False, editable_mode=1, group=None, publication_section=None, document_scanner_gadget=None, active_process_url=None, **kw</string> </value> <value> <string></string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>Base_storeDocumentFromCameraInActiveProcess</string> </value> <value> <string>ActiveProcess_removeItselfFromActivityTool</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
from Products.ZSQLCatalog.SQLCatalog import SimpleQuery
portal = context.getPortalObject()
portal.portal_catalog.searchAndActivate(
portal_type=["Active Process",],
method_id='ActiveProcess_removeItselfFromActivityTool',
reference=context.Base_getDocumentScannerDefaultReference(),
# Active Process don't have creation date set
modification_date=SimpleQuery(
modification_date=(DateTime()-4).earliestTime(),
comparison_operator="<")
)
...@@ -50,19 +50,11 @@ ...@@ -50,19 +50,11 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>active_process</string> </value> <value> <string></string> </value>
</item>
<item>
<key> <string>_proxy_roles</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>Base_removeActiveProcessFromActivityTool</string> </value> <value> <string>Alarm_removeOutdatedActiveProcess</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
import json
active_process = context.getPortalObject().portal_activities.newActiveProcess(
  • @romain this is something only Manager can do I think.

    Is that good for such a use cases? And what way would we have to allow it for other users, I can think only of Proxy Role or change ActivityTool, which I do not know if it is a good idea.

  • The idea here is to temporary store the image outside any module to reduce as much as possible ZODB modification in some cases.

    Looking at deferred style, it seems it also uses a Manager Proxy Role.

    Can you check if a Manager role is also needed to update the Active Process?

    /cc @gabriel

  • Can you check if a Manager role is also needed to update the Active Process?

    I am not really sure how it is used here. I think its usage is boiled to getting the image via getResultList in Base_getTempImageList

    And this seems to require also manager

  • Ah, and Base_getTempImageList seems to have Manager

    So maybe we do add also here?

  • I guess so

    Or maybe @kazuhiko has a better proposal?

  • We already discussed with @kazuhiko on Jabber and he is of same opinion. I pinged you as the author of the script in case we mix the generic use case here.. So I will add the proxy role

  • Done in c5f05bf6

  • @georgios.dagkakis, Thank you for fixing it

    Indeed, we miss a proxy role in this script. I update my instance and make sure the tests with a normal user instead of superuser

Please register or sign in to reply
reference=context.Base_getDocumentScannerDefaultReference())
return json.dumps({
"active_process": active_process.getRelativeUrl(),
"image_list": []
})
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_getDocumentScannerDefaultBackendDataAsJSON</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_getDocumentScannerDefaultReference</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -7,6 +7,5 @@ selection_mapping = portal.portal_selections.getSelectionParamsFor( ...@@ -7,6 +7,5 @@ selection_mapping = portal.portal_selections.getSelectionParamsFor(
REQUEST=context.REQUEST) or {} REQUEST=context.REQUEST) or {}
canvas_data = selection_mapping.get(context.REQUEST["HTTP_USER_AGENT"]) or {} canvas_data = selection_mapping.get(context.REQUEST["HTTP_USER_AGENT"]) or {}
canvas_data["dialog_method"] = context.Base_storeDocumentFromCameraInActiveProcess.getId()
return json.dumps(canvas_data) return json.dumps(canvas_data)
import json
preference_tool = context.getPortalObject().portal_preferences
setting_dict = {
"compression": preference_tool.getPreferredImageScannerConversionCompression(),
"enable_greyscale": preference_tool.getPreferredImageScannerConversionEnableGreyscale(),
"brightness": preference_tool.getPreferredImageScannerConversionBrightness(),
"contrast": preference_tool.getPreferredImageScannerConversionContrast(),
}
return json.dumps(setting_dict)
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_getPreferredImageSettingsFromPreference</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
""" """
Proxy role as Manager is required here to access getResultList Proxy role as Manager is required here to access getResultList
""" """
from base64 import decodestring
if REQUEST: if REQUEST:
return RuntimeError("You cannot run this script in the url") return RuntimeError("You cannot run this script in the url")
...@@ -8,9 +9,10 @@ image_module = context.getPortalObject().image_module ...@@ -8,9 +9,10 @@ image_module = context.getPortalObject().image_module
pdf_data_list = [] pdf_data_list = []
for result in active_process.getResultList(): for result in active_process.getResultList():
pdf_data_list.append( if result.reference in image_list:
image_module.newContent(data=result.detail, pdf_data_list.append(
portal_type="Image", image_module.newContent(data=decodestring(result.detail),
temp_object=True).convert(format="pdf")[1]) portal_type="Image",
temp_object=True).convert(format="pdf")[1])
return pdf_data_list return pdf_data_list
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>active_process, REQUEST=None</string> </value> <value> <string>active_process, image_list, REQUEST=None</string> </value>
</item> </item>
<item> <item>
<key> <string>_proxy_roles</string> </key> <key> <string>_proxy_roles</string> </key>
......
...@@ -2,16 +2,26 @@ ...@@ -2,16 +2,26 @@
We need proy role as manager to create a new active process We need proy role as manager to create a new active process
and post active result and post active result
""" """
import string
import random
portal = context.getPortalObject() portal = context.getPortalObject()
if REQUEST: if REQUEST:
return RuntimeError("You cannot run this script in the url") return RuntimeError("You cannot run this script in the url")
reference = context.Base_getDocumentScannerDefaultReference()
if active_process_url: if active_process_url:
active_process = portal.restrictedTraverse(active_process_url) active_process = portal.restrictedTraverse(active_process_url)
else: else:
active_process = portal.portal_activities.newActiveProcess() active_process = portal.portal_activities.newActiveProcess(
reference=reference)
active_process.postActiveResult(detail=detail) if generate_new_uid:
id_group = (reference, active_process.getUid())
new_uid = portal.portal_ids.generateNewId(id_group=id_group, default=0)
else:
new_uid = None
return active_process active_process.postActiveResult(detail=detail, reference=new_uid)
return active_process, new_uid
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>active_process_url, detail, REQUEST=None, **kw</string> </value> <value> <string>active_process_url, detail, generate_new_uid=False, REQUEST=None, **kw</string> </value>
</item> </item>
<item> <item>
<key> <string>_proxy_roles</string> </key> <key> <string>_proxy_roles</string> </key>
......
context.getPortalObject().portal_activities.manage_delObjects(
ids=[active_process.getId(),])
import json
from base64 import decodestring
portal = context.getPortalObject()
translateString = portal.Base_translateString
gadget_data = json.loads(document_scanner_gadget)
image_str = decodestring(gadget_data.pop("input_value"))
preferred_cropped_canvas_data = gadget_data["preferred_cropped_canvas_data"] or {}
selection_mapping = portal.portal_selections.getSelectionParamsFor(
context.Base_getDocumentScannerSelectionName(),
REQUEST=context.REQUEST) or {}
http_user_agent = context.REQUEST["HTTP_USER_AGENT"]
selection_mapping[http_user_agent] = preferred_cropped_canvas_data
portal.portal_selections.setSelectionParamsFor(
context.Base_getDocumentScannerSelectionName(),
selection_mapping,
context.REQUEST
)
if not image_str:
if batch_mode:
if active_process_url:
return portal.restrictedTraverse(active_process_url)
return None
return context.Base_renderForm('Base_viewUploadDocumentFromCameraDialog',
message=translateString('Nothing to capture'))
active_process = context.Base_postDataToActiveResult(
active_process_url,
image_str)
# We need it to fill the form rendered by renderjs
context.REQUEST.form["your_active_process_url"] = active_process.getRelativeUrl()
# We remove it to reduce the size of the response
context.REQUEST.form.pop("field_your_document_scanner_gadget")
context.REQUEST.form.pop('document_scanner_gadget')
if batch_mode:
return active_process
return context.Base_renderForm('Base_viewUploadDocumentFromCameraDialog',
message=translateString('Captured'))
import json
_, uuid = context.Base_postDataToActiveResult(
active_process_url, input_value,
generate_new_uid=True)
return json.dumps({"uuid": uuid})
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>input_value, active_process_url, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_storeNewImageCropped</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -5,9 +5,9 @@ class StringIOWithFileName(StringIO): ...@@ -5,9 +5,9 @@ class StringIOWithFileName(StringIO):
kw.get("title") or DateTime().strftime('%d-%m-%Y_%Hh%M')) kw.get("title") or DateTime().strftime('%d-%m-%Y_%Hh%M'))
portal = context.getPortalObject() portal = context.getPortalObject()
active_process = portal.restrictedTraverse(active_process_url) active_process = portal.restrictedTraverse(str(active_process_url))
pdf_data_list = context.Base_getTempImageList(active_process) pdf_data_list = context.Base_getTempImageList(active_process, image_list)
pdf_data = context.ERP5Site_mergePDFList(pdf_data_list=pdf_data_list) pdf_data = context.ERP5Site_mergePDFList(pdf_data_list=pdf_data_list)
file_object = StringIOWithFileName(pdf_data) file_object = StringIOWithFileName(pdf_data)
...@@ -26,5 +26,3 @@ else: ...@@ -26,5 +26,3 @@ else:
for action in action_list: for action in action_list:
getattr(doc, action)() getattr(doc, action)()
context.Base_removeActiveProcessFromActivityTool(active_process)
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>publication_state, active_process_url=None, **kw</string> </value> <value> <string>publication_state, active_process_url, image_list, **kw</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
import json
data_dict = json.loads(data_json)
portal = context.getPortalObject() portal = context.getPortalObject()
translateString = portal.Base_translateString translateString = portal.Base_translateString
active_process = context.Base_storeDocumentFromCameraInActiveProcess( active_process_url = data_dict.pop("active_process")
active_process_url=active_process_url, image_list = data_dict.pop("image_list")
batch_mode=True,
**kw) preferred_cropped_canvas_data = data_dict.pop("preferred_cropped_canvas_data") or {}
selection_mapping = portal.portal_selections.getSelectionParamsFor(
context.Base_getDocumentScannerSelectionName(),
REQUEST=context.REQUEST) or {}
http_user_agent = context.REQUEST["HTTP_USER_AGENT"]
selection_mapping[http_user_agent] = preferred_cropped_canvas_data or {}
portal.portal_selections.setSelectionParamsFor(
context.Base_getDocumentScannerSelectionName(),
selection_mapping,
context.REQUEST
)
# Avoid to pass huge images to the activity # Avoid to pass huge images to the activity
kw.pop("your_document_scanner_gadget", None) kw.pop("your_document_scanner_gadget", None)
context.activate().Base_uploadDocumentFromCamera( context.activate().Base_uploadDocumentFromCamera(
active_process_url=active_process.getRelativeUrl(), publication_state=publication_state,
active_process_url=active_process_url,
image_list=image_list,
**kw) **kw)
return context.Base_redirect('view', return context.Base_redirect('view',
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>active_process_url=None, **kw</string> </value> <value> <string>data_json, publication_state, **kw</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -95,7 +95,6 @@ ...@@ -95,7 +95,6 @@
<key> <string>left</string> </key> <key> <string>left</string> </key>
<value> <value>
<list> <list>
<string>your_active_process_url</string>
<string>your_document_scanner_gadget</string> <string>your_document_scanner_gadget</string>
</list> </list>
</value> </value>
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list> <list>
<string>default</string>
<string>gadget_url</string> <string>gadget_url</string>
<string>renderjs_extra</string> <string>renderjs_extra</string>
<string>title</string> <string>title</string>
...@@ -51,6 +52,12 @@ ...@@ -51,6 +52,12 @@
<key> <string>tales</string> </key> <key> <string>tales</string> </key>
<value> <value>
<dictionary> <dictionary>
<item>
<key> <string>default</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
...@@ -61,18 +68,20 @@ ...@@ -61,18 +68,20 @@
</item> </item>
<item> <item>
<key> <string>gadget_url</string> </key> <key> <string>gadget_url</string> </key>
<value> <string></string> </value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item> </item>
<item> <item>
<key> <string>renderjs_extra</string> </key> <key> <string>renderjs_extra</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</value> </value>
</item> </item>
<item> <item>
...@@ -86,6 +95,10 @@ ...@@ -86,6 +95,10 @@
<key> <string>values</string> </key> <key> <string>values</string> </key>
<value> <value>
<dictionary> <dictionary>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string>my_gadget_field</string> </value> <value> <string>my_gadget_field</string> </value>
...@@ -96,7 +109,7 @@ ...@@ -96,7 +109,7 @@
</item> </item>
<item> <item>
<key> <string>gadget_url</string> </key> <key> <string>gadget_url</string> </key>
<value> <string>gadget_document_scanner.html</string> </value> <value> <string></string> </value>
</item> </item>
<item> <item>
<key> <string>renderjs_extra</string> </key> <key> <string>renderjs_extra</string> </key>
...@@ -126,12 +139,38 @@ ...@@ -126,12 +139,38 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>_text</string> </key> <key> <string>_text</string> </key>
<value> <string>python: [(\'dialog_method\', \'Base_storeDocumentFromCameraInActiveProcess\'), (\'preferred_cropped_canvas_data\', context.Base_getPreferredCropperSettingsFromSelection()),]</string> </value> <value> <string>python: here.Base_getDocumentScannerDefaultBackendDataAsJSON()</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="3" aka="AAAAAAAAAAM="> <record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>string: gadget_document_scanner.html</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: [(\'preferred_image_settings_data\', context.Base_getPreferredImageSettingsFromPreference()), (\'preferred_cropped_canvas_data\', context.Base_getPreferredCropperSettingsFromSelection()), ("store_new_image_cropped_method", \'Base_storeNewImageCropped\')]</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="5" aka="AAAAAAAAAAU=">
<pickle> <pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/> <global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle> </pickle>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ERP5 Form" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>action</string> </key>
<value> <string>Base_edit</string> </value>
</item>
<item>
<key> <string>action_title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>edit_order</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>enctype</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>group_list</string> </key>
<value>
<list>
<string>left</string>
<string>right</string>
<string>center</string>
</list>
</value>
</item>
<item>
<key> <string>groups</string> </key>
<value>
<dictionary>
<item>
<key> <string>center</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>left</string> </key>
<value>
<list>
<string>my_preferred_image_scanner_conversion_enable_greyscale</string>
</list>
</value>
</item>
<item>
<key> <string>right</string> </key>
<value>
<list>
<string>my_preferred_image_scanner_conversion_compression</string>
<string>my_preferred_image_scanner_conversion_brightness</string>
<string>my_preferred_image_scanner_conversion_contrast</string>
</list>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Preference_viewDocumentScannerSetting</string> </value>
</item>
<item>
<key> <string>method</string> </key>
<value> <string>POST</string> </value>
</item>
<item>
<key> <string>name</string> </key>
<value> <string>Preference_viewDocumentScannerSettting</string> </value>
</item>
<item>
<key> <string>pt</string> </key>
<value> <string>form_view</string> </value>
</item>
<item>
<key> <string>row_length</string> </key>
<value> <int>4</int> </value>
</item>
<item>
<key> <string>stored_encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Document Scanner</string> </value>
</item>
<item>
<key> <string>unicode_mode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>update_action</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>update_action_title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_preferred_image_scanner_conversion_brightness</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_float_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Brightness [-100 .. 100]</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_preferred_image_scanner_conversion_compression</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_float_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Image compression [0 .. 1]</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_preferred_image_scanner_conversion_contrast</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_integer_value</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Contrast [-100 .. 100]</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -10,13 +10,13 @@ ...@@ -10,13 +10,13 @@
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list> <list>
<string>hidden</string> <string>title</string>
</list> </list>
</value> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>your_active_process_url</string> </value> <value> <string>my_preferred_image_scanner_conversion_enable_greyscale</string> </value>
</item> </item>
<item> <item>
<key> <string>message_values</string> </key> <key> <string>message_values</string> </key>
...@@ -73,20 +73,20 @@ ...@@ -73,20 +73,20 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string>my_string_field</string> </value> <value> <string>your_checkbox</string> </value>
</item> </item>
<item> <item>
<key> <string>form_id</string> </key> <key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value> <value> <string>Base_viewFieldLibrary</string> </value>
</item> </item>
<item>
<key> <string>hidden</string> </key>
<value> <int>1</int> </value>
</item>
<item> <item>
<key> <string>target</string> </key> <key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value> <value> <string>Click to edit the target</string> </value>
</item> </item>
<item>
<key> <string>title</string> </key>
<value> <string>Enable Greyscale</string> </value>
</item>
</dictionary> </dictionary>
</value> </value>
</item> </item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Cacheable__manager_id</string> </key>
<value> <string>must_revalidate_http_cache</string> </value>
</item>
<item>
<key> <string>__name__</string> </key>
<value> <string>caman.full.min.js</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/javascript</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>caman.full.min.js</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
/*! /*!
* Cropper.js v1.5.1 * Cropper.js v1.5.6
* https://fengyuanchen.github.io/cropperjs * https://fengyuanchen.github.io/cropperjs
* *
* Copyright 2015-present Chen Fengyuan * Copyright 2015-present Chen Fengyuan
* Released under the MIT license * Released under the MIT license
* *
* Date: 2019-03-10T09:55:50.492Z * Date: 2019-10-04T04:33:44.164Z
*/.cropper-container{direction:ltr;font-size:0;line-height:0;position:relative;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.cropper-container img{display:block;height:100%;image-orientation:0deg;max-height:none!important;max-width:none!important;min-height:0!important;min-width:0!important;width:100%}.cropper-canvas,.cropper-crop-box,.cropper-drag-box,.cropper-modal,.cropper-wrap-box{bottom:0;left:0;position:absolute;right:0;top:0}.cropper-canvas,.cropper-wrap-box{overflow:hidden}.cropper-drag-box{background-color:#fff;opacity:0}.cropper-modal{background-color:#000;opacity:.5}.cropper-view-box{display:block;height:100%;outline:1px solid #39f;outline-color:rgba(51,153,255,.75);overflow:hidden;width:100%}.cropper-dashed{border:0 dashed #eee;display:block;opacity:.5;position:absolute}.cropper-dashed.dashed-h{border-bottom-width:1px;border-top-width:1px;height:33.33333%;left:0;top:33.33333%;width:100%}.cropper-dashed.dashed-v{border-left-width:1px;border-right-width:1px;height:100%;left:33.33333%;top:0;width:33.33333%}.cropper-center{display:block;height:0;left:50%;opacity:.75;position:absolute;top:50%;width:0}.cropper-center:after,.cropper-center:before{background-color:#eee;content:" ";display:block;position:absolute}.cropper-center:before{height:1px;left:-3px;top:0;width:7px}.cropper-center:after{height:7px;left:0;top:-3px;width:1px}.cropper-face,.cropper-line,.cropper-point{display:block;height:100%;opacity:.1;position:absolute;width:100%}.cropper-face{background-color:#fff;left:0;top:0}.cropper-line{background-color:#39f}.cropper-line.line-e{cursor:ew-resize;right:-3px;top:0;width:5px}.cropper-line.line-n{cursor:ns-resize;height:5px;left:0;top:-3px}.cropper-line.line-w{cursor:ew-resize;left:-3px;top:0;width:5px}.cropper-line.line-s{bottom:-3px;cursor:ns-resize;height:5px;left:0}.cropper-point{background-color:#39f;height:5px;opacity:.75;width:5px}.cropper-point.point-e{cursor:ew-resize;margin-top:-3px;right:-3px;top:50%}.cropper-point.point-n{cursor:ns-resize;left:50%;margin-left:-3px;top:-3px}.cropper-point.point-w{cursor:ew-resize;left:-3px;margin-top:-3px;top:50%}.cropper-point.point-s{bottom:-3px;cursor:s-resize;left:50%;margin-left:-3px}.cropper-point.point-ne{cursor:nesw-resize;right:-3px;top:-3px}.cropper-point.point-nw{cursor:nwse-resize;left:-3px;top:-3px}.cropper-point.point-sw{bottom:-3px;cursor:nesw-resize;left:-3px}.cropper-point.point-se{bottom:-3px;cursor:nwse-resize;height:20px;opacity:1;right:-3px;width:20px}@media (min-width:768px){.cropper-point.point-se{height:15px;width:15px}}@media (min-width:992px){.cropper-point.point-se{height:10px;width:10px}}@media (min-width:1200px){.cropper-point.point-se{height:5px;opacity:.75;width:5px}}.cropper-point.point-se:before{background-color:#39f;bottom:-50%;content:" ";display:block;height:200%;opacity:0;position:absolute;right:-50%;width:200%}.cropper-invisible{opacity:0}.cropper-bg{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC")}.cropper-hide{display:block;height:0;position:absolute;width:0}.cropper-hidden{display:none!important}.cropper-move{cursor:move}.cropper-crop{cursor:crosshair}.cropper-disabled .cropper-drag-box,.cropper-disabled .cropper-face,.cropper-disabled .cropper-line,.cropper-disabled .cropper-point{cursor:not-allowed} */.cropper-container{direction:ltr;font-size:0;line-height:0;position:relative;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.cropper-container img{display:block;height:100%;image-orientation:0deg;max-height:none!important;max-width:none!important;min-height:0!important;min-width:0!important;width:100%}.cropper-canvas,.cropper-crop-box,.cropper-drag-box,.cropper-modal,.cropper-wrap-box{bottom:0;left:0;position:absolute;right:0;top:0}.cropper-canvas,.cropper-wrap-box{overflow:hidden}.cropper-drag-box{background-color:#fff;opacity:0}.cropper-modal{background-color:#000;opacity:.5}.cropper-view-box{display:block;height:100%;outline:1px solid #39f;outline-color:rgba(51,153,255,.75);overflow:hidden;width:100%}.cropper-dashed{border:0 dashed #eee;display:block;opacity:.5;position:absolute}.cropper-dashed.dashed-h{border-bottom-width:1px;border-top-width:1px;height:33.33333%;left:0;top:33.33333%;width:100%}.cropper-dashed.dashed-v{border-left-width:1px;border-right-width:1px;height:100%;left:33.33333%;top:0;width:33.33333%}.cropper-center{display:block;height:0;left:50%;opacity:.75;position:absolute;top:50%;width:0}.cropper-center:after,.cropper-center:before{background-color:#eee;content:" ";display:block;position:absolute}.cropper-center:before{height:1px;left:-3px;top:0;width:7px}.cropper-center:after{height:7px;left:0;top:-3px;width:1px}.cropper-face,.cropper-line,.cropper-point{display:block;height:100%;opacity:.1;position:absolute;width:100%}.cropper-face{background-color:#fff;left:0;top:0}.cropper-line{background-color:#39f}.cropper-line.line-e{cursor:ew-resize;right:-3px;top:0;width:5px}.cropper-line.line-n{cursor:ns-resize;height:5px;left:0;top:-3px}.cropper-line.line-w{cursor:ew-resize;left:-3px;top:0;width:5px}.cropper-line.line-s{bottom:-3px;cursor:ns-resize;height:5px;left:0}.cropper-point{background-color:#39f;height:5px;opacity:.75;width:5px}.cropper-point.point-e{cursor:ew-resize;margin-top:-3px;right:-3px;top:50%}.cropper-point.point-n{cursor:ns-resize;left:50%;margin-left:-3px;top:-3px}.cropper-point.point-w{cursor:ew-resize;left:-3px;margin-top:-3px;top:50%}.cropper-point.point-s{bottom:-3px;cursor:s-resize;left:50%;margin-left:-3px}.cropper-point.point-ne{cursor:nesw-resize;right:-3px;top:-3px}.cropper-point.point-nw{cursor:nwse-resize;left:-3px;top:-3px}.cropper-point.point-sw{bottom:-3px;cursor:nesw-resize;left:-3px}.cropper-point.point-se{bottom:-3px;cursor:nwse-resize;height:20px;opacity:1;right:-3px;width:20px}@media (min-width:768px){.cropper-point.point-se{height:15px;width:15px}}@media (min-width:992px){.cropper-point.point-se{height:10px;width:10px}}@media (min-width:1200px){.cropper-point.point-se{height:5px;opacity:.75;width:5px}}.cropper-point.point-se:before{background-color:#39f;bottom:-50%;content:" ";display:block;height:200%;opacity:0;position:absolute;right:-50%;width:200%}.cropper-invisible{opacity:0}.cropper-bg{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC")}.cropper-hide{display:block;height:0;position:absolute;width:0}.cropper-hidden{display:none!important}.cropper-move{cursor:move}.cropper-crop{cursor:crosshair}.cropper-disabled .cropper-drag-box,.cropper-disabled .cropper-face,.cropper-disabled .cropper-line,.cropper-disabled .cropper-point{cursor:not-allowed}
\ No newline at end of file
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>_Cacheable__manager_id</string> </key> <key> <string>_Cacheable__manager_id</string> </key>
<value> <string>http_cache</string> </value> <value> <string>must_revalidate_http_cache</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>_Cacheable__manager_id</string> </key> <key> <string>_Cacheable__manager_id</string> </key>
<value> <string>http_cache</string> </value> <value> <string>must_revalidate_http_cache</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
</item> </item>
<item> <item>
<key> <string>content_type</string> </key> <key> <string>content_type</string> </key>
<value> <string>application/x-javascript</string> </value> <value> <string>text/javascript</string> </value>
</item> </item>
<item> <item>
<key> <string>precondition</string> </key> <key> <string>precondition</string> </key>
......
Accounting Transaction | scan_document Accounting Transaction | scan_document
Internal Invoice Transaction | scan_document Internal Invoice Transaction | scan_document
Payment Transaction | scan_document Payment Transaction | scan_document
Preference | document_scanner_preference
Purchase Invoice Transaction | scan_document Purchase Invoice Transaction | scan_document
Sale Invoice Transaction | scan_document Sale Invoice Transaction | scan_document
\ No newline at end of file
web_page_module/rjs_gadget_document_scanner_css
web_page_module/rjs_gadget_document_scanner_html
web_page_module/rjs_gadget_document_scanner_js
\ No newline at end of file
portal_alarms/remove_outdated_document_scanner_active_processes
web_page_module/rjs_gadget_document_scanner_css web_page_module/rjs_gadget_document_scanner_css
web_page_module/rjs_gadget_document_scanner_html web_page_module/rjs_gadget_document_scanner_html
web_page_module/rjs_gadget_document_scanner_js web_page_module/rjs_gadget_document_scanner_js
\ No newline at end of file
Active Process | Reference
\ No newline at end of file
...@@ -101,20 +101,15 @@ ...@@ -101,20 +101,15 @@
<td>//button[@class="take-picture-btn ui-btn-icon-left ui-icon-circle"]</td> <td>//button[@class="take-picture-btn ui-btn-icon-left ui-icon-circle"]</td>
<td></td> <td></td>
</tr> </tr>
<tr>
<td>waitForCondition</td>
<td>selenium.browserbot.getCurrentWindow().document.querySelector("video").readyState == 4</td>
<td>30000</td>
</tr>
<tr> <tr>
<td>click</td> <td>click</td>
<td>//button[@class="take-picture-btn ui-btn-icon-left ui-icon-circle"]</td> <td>//button[@class="take-picture-btn ui-btn-icon-left ui-icon-circle"]</td>
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
<td>waitForCondition</td> <td>waitForElementPresent</td>
<td>selenium.browserbot.getCurrentWindow().document.querySelector(".confirm-btn").style.display != "none"</td> <td>//button[@class="reset-btn ui-btn-icon-left ui-icon-times"]</td>
<td>30000</td> <td></td>
</tr> </tr>
<tr> <tr>
<td>click</td> <td>click</td>
...@@ -122,9 +117,9 @@ ...@@ -122,9 +117,9 @@
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
<td>waitForCondition</td> <td>waitForElementPresent</td>
<td>selenium.browserbot.getCurrentWindow().document.querySelector(".confirm-btn").style.display == "none"</td> <td>//button[@class="take-picture-btn ui-btn-icon-left ui-icon-circle"]</td>
<td>30000</td> <td></td>
</tr> </tr>
<tr> <tr>
<td>click</td> <td>click</td>
...@@ -132,9 +127,9 @@ ...@@ -132,9 +127,9 @@
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
<td>waitForCondition</td> <td>waitForElementPresent</td>
<td>selenium.browserbot.getCurrentWindow().document.querySelector(".confirm-btn").style.display != "none"</td> <td>//button[@class="confirm-btn ui-btn-icon-left ui-icon-check"]</td>
<td>3000</td> <td></td>
</tr> </tr>
<tr> <tr>
<td>click</td> <td>click</td>
...@@ -149,11 +144,6 @@ ...@@ -149,11 +144,6 @@
</div> </div>
<!--tr>
<td>waitForCondition</td>
<td>selenium.browserbot.getCurrentWindow().document.querySelector(".page-number").innerText == "2"</td>
<td>30000</td>
</tr-->
<tr> <tr>
<td>storeValue</td> <td>storeValue</td>
<td>//input[@id="field_your_active_process_url"]</td> <td>//input[@id="field_your_active_process_url"]</td>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment