Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
O
osticket
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container registry
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
docker
osticket
Commits
f6b218a4
Commit
f6b218a4
authored
10 years ago
by
Jared Hancock
Browse files
Options
Downloads
Patches
Plain Diff
draft: Migrate Draft to use ORM
parent
8076a7f7
Branches
Branches containing commit
Tags
Tags containing commit
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
include/ajax.draft.php
+18
-20
18 additions, 20 deletions
include/ajax.draft.php
include/class.draft.php
+76
-67
76 additions, 67 deletions
include/class.draft.php
js/redactor-osticket.js
+54
-68
54 additions, 68 deletions
js/redactor-osticket.js
with
148 additions
and
155 deletions
include/ajax.draft.php
+
18
−
20
View file @
f6b218a4
...
@@ -7,29 +7,24 @@ require_once(INCLUDE_DIR.'class.draft.php');
...
@@ -7,29 +7,24 @@ require_once(INCLUDE_DIR.'class.draft.php');
class
DraftAjaxAPI
extends
AjaxController
{
class
DraftAjaxAPI
extends
AjaxController
{
function
_createDraft
(
$vars
)
{
function
_createDraft
(
$vars
)
{
$field_list
=
array
(
'response'
,
'note'
,
'answer'
,
'body'
,
if
(
!
isset
(
$vars
[
'body'
]))
{
'message'
,
'issue'
);
$field_list
=
array
(
'response'
,
'note'
,
'answer'
,
'body'
,
foreach
(
$field_list
as
$field
)
{
'message'
,
'issue'
);
if
(
isset
(
$_POST
[
$field
]))
{
foreach
(
$field_list
as
$field
)
{
$vars
[
'body'
]
=
urldecode
(
$_POST
[
$field
]);
if
(
isset
(
$_POST
[
$field
]))
{
break
;
$vars
[
'body'
]
=
$_POST
[
$field
];
break
;
}
}
}
}
}
if
(
!
isset
(
$vars
[
'body'
]))
if
(
!
isset
(
$vars
[
'body'
])
||
!
$vars
[
'body'
])
return
Http
::
response
(
422
,
"Draft body not found in request"
);
return
JsonDataEncoder
::
encode
(
array
(
'error'
=>
__
(
"Draft body not found in request"
),
'code'
=>
422
,
));
$errors
=
array
();
if
(
!
(
$draft
=
Draft
::
create
(
$vars
))
||
!
$draft
->
save
())
if
(
!
(
$draft
=
Draft
::
create
(
$vars
,
$errors
)))
Http
::
response
(
500
,
'Unable to create draft'
);
Http
::
response
(
500
,
print_r
(
$errors
,
true
));
// If the draft is created from an existing document, ensure inline
// attachments from the cloned document are attachned to the draft
// XXX: Actually, I think this is just wasting time, because the
// other object already has the items attached, so the database
// won't clean up the files. They don't have to be attached to
// the draft for Draft::getAttachmentIds to return the id of the
// attached file
//$draft->syncExistingAttachments();
echo
JsonDataEncoder
::
encode
(
array
(
echo
JsonDataEncoder
::
encode
(
array
(
'draft_id'
=>
$draft
->
getId
(),
'draft_id'
=>
$draft
->
getId
(),
...
@@ -232,6 +227,9 @@ class DraftAjaxAPI extends AjaxController {
...
@@ -232,6 +227,9 @@ class DraftAjaxAPI extends AjaxController {
'namespace'
=>
$namespace
,
'namespace'
=>
$namespace
,
);
);
if
(
isset
(
$_POST
[
'name'
]))
$vars
[
'body'
]
=
$_POST
[
$_POST
[
'name'
]];
return
self
::
_createDraft
(
$vars
);
return
self
::
_createDraft
(
$vars
);
}
}
...
...
This diff is collapsed.
Click to expand it.
include/class.draft.php
+
76
−
67
View file @
f6b218a4
<?php
<?php
class
Draft
{
/**
* Class: Draft
var
$id
;
*
var
$ht
;
* Defines a simple draft-saving mechanism for osTicket which supports draft
* fetch and update via an ajax mechanism (include/ajax.draft.php).
var
$_attachments
;
*
* Fields:
function
Draft
(
$id
)
{
* id - (int:auto:pk) Draft ID number
$this
->
id
=
$id
;
* body - (text) Body of the draft
$this
->
load
();
* namespace - (string) Identifier of draft grouping — useful for multiple
}
* drafts on the same document by different users
* staff_id - (int:null) Staff owner of the draft
function
load
()
{
* extra - (text:json) Extra attributes of the draft
$this
->
attachments
=
new
GenericAttachments
(
$this
->
id
,
'D'
);
* created - (date) Date draft was initially created
$sql
=
'SELECT * FROM '
.
DRAFT_TABLE
.
' WHERE id='
.
db_input
(
$this
->
id
);
* updated - (date:null) Date draft was last updated
return
((
$res
=
db_query
(
$sql
))
*/
&&
(
$this
->
ht
=
db_fetch_array
(
$res
)));
class
Draft
extends
VerySimpleModel
{
static
$meta
=
array
(
'table'
=>
DRAFT_TABLE
,
'pk'
=>
array
(
'id'
),
);
var
$attachments
;
function
__construct
()
{
call_user_func_array
(
array
(
'parent'
,
'__construct'
),
func_get_args
());
if
(
isset
(
$this
->
id
))
$this
->
attachments
=
new
GenericAttachments
(
$this
->
id
,
'D'
);
}
}
function
getId
()
{
return
$this
->
id
;
}
function
getId
()
{
return
$this
->
id
;
}
function
getBody
()
{
return
$this
->
ht
[
'body'
];
}
function
getBody
()
{
return
$this
->
body
;
}
function
getStaffId
()
{
return
$this
->
ht
[
'staff_id'
];
}
function
getStaffId
()
{
return
$this
->
staff_id
;
}
function
getNamespace
()
{
return
$this
->
ht
[
'namespace'
];
}
function
getNamespace
()
{
return
$this
->
namespace
;
}
static
function
getDraftAndDataAttrs
(
$namespace
,
$id
=
0
,
$original
=
''
)
{
$draft_body
=
null
;
$attrs
=
array
(
sprintf
(
'data-draft-namespace="%s"'
,
$namespace
));
$criteria
=
array
(
'namespace'
=>
$namespace
);
if
(
$id
)
{
$attrs
[]
=
sprintf
(
'data-draft-object-id="%s"'
,
$id
);
$criteria
[
'namespace'
]
.
=
'.'
.
$id
;
}
if
(
$draft
=
static
::
lookup
(
$criteria
))
{
$attrs
[]
=
sprintf
(
'data-draft-id="%s"'
,
$draft
->
getId
());
$draft_body
=
$draft
->
getBody
();
}
$attrs
[]
=
sprintf
(
'data-draft-original="%s"'
,
Format
::
htmlchars
(
$original
));
return
array
(
$draft_body
,
implode
(
' '
,
$attrs
));
}
function
getAttachmentIds
(
$body
=
false
)
{
function
getAttachmentIds
(
$body
=
false
)
{
$attachments
=
array
();
$attachments
=
array
();
...
@@ -63,69 +92,49 @@ class Draft {
...
@@ -63,69 +92,49 @@ class Draft {
function
setBody
(
$body
)
{
function
setBody
(
$body
)
{
// Change image.php urls back to content-id's
// Change image.php urls back to content-id's
$body
=
Format
::
sanitize
(
$body
,
false
);
$body
=
Format
::
sanitize
(
$body
,
false
);
$this
->
ht
[
'body'
]
=
$body
;
$sql
=
'UPDATE '
.
DRAFT_TABLE
.
' SET updated=NOW()'
$this
->
body
=
$body
;
.
',body='
.
db_input
(
$body
)
$this
->
updated
=
SqlFunction
::
NOW
();
.
' WHERE id='
.
db_input
(
$this
->
getId
());
return
$this
->
save
();
return
db_query
(
$sql
)
&&
db_affected_rows
()
==
1
;
}
}
function
delete
()
{
function
delete
()
{
$this
->
attachments
->
deleteAll
();
$this
->
attachments
->
deleteAll
();
$sql
=
'DELETE FROM '
.
DRAFT_TABLE
return
parent
::
delete
();
.
' WHERE id='
.
db_input
(
$this
->
getId
());
return
(
db_query
(
$sql
)
&&
db_affected_rows
()
==
1
);
}
}
function
save
(
$id
,
$vars
,
&
$errors
)
{
function
isValid
(
)
{
// Required fields
// Required fields
if
(
!
$vars
[
'namespace'
]
||
!
isset
(
$vars
[
'body'
])
||
!
isset
(
$vars
[
'staff_id'
]))
return
$this
->
namespace
&&
isset
(
$this
->
body
)
&&
isset
(
$this
->
staff_id
);
}
function
save
(
$refetch
=
false
)
{
if
(
!
$this
->
isValid
())
return
false
;
return
false
;
$sql
=
' SET `namespace`='
.
db_input
(
$vars
[
'namespace'
])
return
parent
::
save
(
$refetch
);
.
' ,body='
.
db_input
(
Format
::
sanitize
(
$vars
[
'body'
],
false
))
}
.
' ,staff_id='
.
db_input
(
$vars
[
'staff_id'
]);
if
(
!
$id
)
{
static
function
create
(
$vars
)
{
$sql
=
'INSERT INTO '
.
DRAFT_TABLE
.
$sql
$attachments
=
@
$vars
[
'attachments'
];
.
' ,created=NOW()'
;
unset
(
$vars
[
'attachments'
]);
if
(
!
db_query
(
$sql
)
||
!
(
$draft
=
self
::
lookup
(
db_insert_id
())))
return
false
;
// Cloned attachments...
$vars
[
'created'
]
=
SqlFunction
::
NOW
();
if
(
$vars
[
'attachments'
]
&&
is_array
(
$vars
[
'attachments'
]))
$draft
=
parent
::
create
(
$vars
);
$draft
->
attachments
->
upload
(
$vars
[
'attachments'
],
true
);
return
$draft
;
// Cloned attachments ...
}
if
(
false
&&
$attachments
&&
is_array
(
$attachments
))
else
{
// XXX: This won't work until the draft is saved
$sql
=
'UPDATE '
.
DRAFT_TABLE
.
$sql
$draft
->
attachments
->
upload
(
$attachments
,
true
);
.
' WHERE id='
.
db_input
(
$id
);
if
(
db_query
(
$sql
)
&&
db_affected_rows
()
==
1
)
return
$this
;
}
}
function
create
(
$vars
,
&
$errors
)
{
return
self
::
save
(
0
,
$vars
,
$errors
);
}
function
lookup
(
$id
)
{
return
$draft
;
return
(
$id
&&
is_numeric
(
$id
)
&&
(
$d
=
new
Draft
(
$id
))
&&
$d
->
getId
()
==
$id
)
?
$d
:
null
;
}
}
function
findByNamespaceAndStaff
(
$namespace
,
$staff_id
)
{
static
function
lookupByNamespaceAndStaff
(
$namespace
,
$staff_id
)
{
$sql
=
'SELECT id FROM '
.
DRAFT_TABLE
return
static
::
lookup
(
array
(
.
' WHERE `namespace`='
.
db_input
(
$namespace
)
'namespace'
=>
$namespace
,
.
' AND staff_id='
.
db_input
(
$staff_id
);
'staff_id'
=>
$staff_id
if
((
$res
=
db_query
(
$sql
))
&&
(
list
(
$id
)
=
db_fetch_row
(
$res
)))
));
return
$id
;
else
return
false
;
}
}
/**
/**
...
...
This diff is collapsed.
Click to expand it.
js/redactor-osticket.js
+
54
−
68
View file @
f6b218a4
...
@@ -21,10 +21,17 @@ RedactorPlugins.draft = {
...
@@ -21,10 +21,17 @@ RedactorPlugins.draft = {
var
autosave_url
=
'
ajax.php/draft/
'
+
this
.
opts
.
draftNamespace
;
var
autosave_url
=
'
ajax.php/draft/
'
+
this
.
opts
.
draftNamespace
;
if
(
this
.
opts
.
draftObjectId
)
if
(
this
.
opts
.
draftObjectId
)
autosave_url
+=
'
.
'
+
this
.
opts
.
draftObjectId
;
autosave_url
+=
'
.
'
+
this
.
opts
.
draftObjectId
;
this
.
opts
.
autosave
=
autosave_url
;
this
.
opts
.
autosave
=
this
.
opts
.
autoCreateUrl
=
autosave_url
;
this
.
opts
.
autosaveInterval
=
10
;
this
.
opts
.
autosaveInterval
=
10
;
this
.
opts
.
autosaveCallback
=
this
.
setupDraftUpdate
;
this
.
opts
.
autosaveCallback
=
this
.
afterUpdateDraft
;
this
.
opts
.
initCallback
=
this
.
recoverDraft
;
this
.
opts
.
autosaveErrorCallback
=
this
.
autosaveFailed
;
if
(
this
.
opts
.
draftId
)
{
this
.
opts
.
autosave
=
'
ajax.php/draft/
'
+
this
.
opts
.
draftId
;
this
.
opts
.
clipboardUploadUrl
=
this
.
opts
.
imageUpload
=
'
ajax.php/draft/
'
+
this
.
opts
.
draftId
+
'
/attach
'
;
}
this
.
opts
.
imageUploadErrorCallback
=
this
.
displayError
;
this
.
$draft_saved
=
$
(
'
<span>
'
)
this
.
$draft_saved
=
$
(
'
<span>
'
)
.
addClass
(
"
pull-right draft-saved
"
)
.
addClass
(
"
pull-right draft-saved
"
)
...
@@ -33,73 +40,55 @@ RedactorPlugins.draft = {
...
@@ -33,73 +40,55 @@ RedactorPlugins.draft = {
.
text
(
__
(
'
Draft Saved
'
)));
.
text
(
__
(
'
Draft Saved
'
)));
// Float the [Draft Saved] box with the toolbar
// Float the [Draft Saved] box with the toolbar
this
.
$toolbar
.
append
(
this
.
$draft_saved
);
this
.
$toolbar
.
append
(
this
.
$draft_saved
);
// Add [Delete Draft] button to the toolbar
if
(
this
.
opts
.
draftDelete
)
{
if
(
this
.
opts
.
draftDelete
)
{
var
trash
=
this
.
buttonAdd
(
'
deleteDraft
'
,
__
(
'
Delete Draft
'
),
this
.
deleteDraft
);
var
trash
=
this
.
draftDeleteButton
=
this
.
buttonAdd
(
'
deleteDraft
'
,
__
(
'
Delete Draft
'
),
this
.
deleteDraft
);
this
.
buttonAwesome
(
'
deleteDraft
'
,
'
icon-trash
'
);
this
.
buttonAwesome
(
'
deleteDraft
'
,
'
icon-trash
'
);
trash
.
parent
().
addClass
(
'
pull-right
'
);
trash
.
parent
().
addClass
(
'
pull-right
'
);
trash
.
addClass
(
'
delete-draft
'
);
trash
.
addClass
(
'
delete-draft
'
);
if
(
!
this
.
opts
.
draftId
)
trash
.
hide
();
}
}
},
},
recoverDraft
:
function
()
{
afterUpdateDraft
:
function
(
data
)
{
var
self
=
this
;
$
.
ajax
(
this
.
opts
.
autosave
,
{
dataType
:
'
json
'
,
statusCode
:
{
200
:
function
(
json
)
{
self
.
draft_id
=
json
.
draft_id
;
// Replace the current content with the draft, sync, and make
// images editable
self
.
setupDraftUpdate
(
json
);
if
(
!
json
.
body
)
return
;
self
.
set
(
json
.
body
,
false
);
self
.
observeStart
();
},
205
:
function
()
{
// Save empty draft immediately;
var
ai
=
self
.
opts
.
autosaveInterval
;
// Save immediately -- capture the created autosave
// interval and clear it as soon as possible. Note that
// autosave()ing doesn't happen immediately. It happens
// async after the autosaveInterval expires.
self
.
opts
.
autosaveInterval
=
0
;
self
.
autosave
();
var
interval
=
self
.
autosaveInterval
;
setTimeout
(
function
()
{
clearInterval
(
interval
);
},
1
);
// Reinstate previous autosave interval timing
self
.
opts
.
autosaveInterval
=
ai
;
}
}
});
},
setupDraftUpdate
:
function
(
data
)
{
if
(
this
.
get
())
this
.
$draft_saved
.
show
().
delay
(
5000
).
fadeOut
();
// Slight workaround. Signal the 'keyup' event normally signaled
// Slight workaround. Signal the 'keyup' event normally signaled
// from typing in the <textarea>
// from typing in the <textarea>
if
(
$
.
autoLock
&&
this
.
opts
.
draftNamespace
==
'
ticket.response
'
)
if
(
$
.
autoLock
&&
this
.
opts
.
draftNamespace
==
'
ticket.response
'
)
{
if
(
this
.
get
())
if
(
this
.
get
())
$
.
autoLock
.
handleEvent
();
$
.
autoLock
.
handleEvent
();
}
if
(
typeof
data
!=
'
object
'
)
// If the draft was created, a draft_id will be sent back — update
data
=
$
.
parseJSON
(
data
);
// the URL to send updates in the future
if
(
data
.
draft_id
)
{
this
.
opts
.
draftId
=
data
.
draft_id
;
this
.
opts
.
autosave
=
'
ajax.php/draft/
'
+
data
.
draft_id
;
}
if
(
!
data
||
!
data
.
draft_id
)
// Only show the [Draft Saved] notice if there is content in the
// field that has been touched
if
(
this
.
opts
.
draftOriginal
&&
this
.
opts
.
draftOriginal
==
this
.
get
())
{
// No change yet — dont't show the button
return
;
}
if
(
data
)
{
this
.
$draft_saved
.
show
().
delay
(
5000
).
fadeOut
();
}
// Show the button if there is a draft to delete
if
(
this
.
opts
.
draftId
&&
this
.
opts
.
draftDelete
)
this
.
draftDeleteButton
.
show
();
},
autosaveFailed
:
function
(
error
)
{
if
(
error
.
code
==
422
)
// Unprocessable request (Empty message)
return
;
return
;
$
(
'
input[name=draft_id]
'
,
this
.
$box
.
closest
(
'
form
'
))
this
.
displayError
(
error
);
.
val
(
data
.
draft_id
);
// Cancel autosave
this
.
draft_id
=
data
.
draft_id
;
clearInterval
(
this
.
autosaveInterval
);
this
.
opts
.
clipboardUploadUrl
=
this
.
hideDraftSaved
();
this
.
opts
.
imageUpload
=
'
ajax.php/draft/
'
+
data
.
draft_id
+
'
/attach
'
;
this
.
opts
.
imageUploadErrorCallback
=
this
.
displayError
;
this
.
opts
.
original_autosave
=
this
.
opts
.
autosave
;
this
.
opts
.
autosave
=
'
ajax.php/draft/
'
+
data
.
draft_id
;
},
},
displayError
:
function
(
json
)
{
displayError
:
function
(
json
)
{
...
@@ -111,18 +100,19 @@ RedactorPlugins.draft = {
...
@@ -111,18 +100,19 @@ RedactorPlugins.draft = {
},
},
deleteDraft
:
function
()
{
deleteDraft
:
function
()
{
if
(
!
this
.
draft
_i
d
)
if
(
!
this
.
opts
.
draft
I
d
)
// Nothing to delete
// Nothing to delete
return
;
return
;
var
self
=
this
;
var
self
=
this
;
$
.
ajax
(
'
ajax.php/draft/
'
+
this
.
draft
_i
d
,
{
$
.
ajax
(
'
ajax.php/draft/
'
+
this
.
opts
.
draft
I
d
,
{
type
:
'
delete
'
,
type
:
'
delete
'
,
async
:
false
,
async
:
false
,
success
:
function
()
{
success
:
function
()
{
self
.
draft_id
=
undefined
;
self
.
draft_id
=
undefined
;
self
.
hideDraftSaved
();
self
.
hideDraftSaved
();
self
.
set
(
''
,
false
,
false
);
self
.
set
(
self
.
opts
.
draftOriginal
||
''
,
false
,
false
);
self
.
opts
.
autosave
=
self
.
opts
.
original_autosave
;
self
.
opts
.
autosave
=
self
.
opts
.
autoCreateUrl
;
self
.
draftDeleteButton
.
hide
();
}
}
});
});
}
}
...
@@ -141,10 +131,10 @@ RedactorPlugins.signature = {
...
@@ -141,10 +131,10 @@ RedactorPlugins.signature = {
else
else
this
.
$signatureBox
.
hide
();
this
.
$signatureBox
.
hide
();
$
(
'
input[name=
'
+
$el
.
data
(
'
signatureField
'
)
+
'
]
'
,
$el
.
closest
(
'
form
'
))
$
(
'
input[name=
'
+
$el
.
data
(
'
signatureField
'
)
+
'
]
'
,
$el
.
closest
(
'
form
'
))
.
on
(
'
change
'
,
false
,
false
,
$
.
proxy
(
this
.
updateSignature
,
this
))
.
on
(
'
change
'
,
false
,
false
,
$
.
proxy
(
this
.
updateSignature
,
this
))
;
if
(
$el
.
data
(
'
deptField
'
))
if
(
$el
.
data
(
'
deptField
'
))
$
(
'
:input[name=
'
+
$el
.
data
(
'
deptField
'
)
+
'
]
'
,
$el
.
closest
(
'
form
'
))
$
(
'
:input[name=
'
+
$el
.
data
(
'
deptField
'
)
+
'
]
'
,
$el
.
closest
(
'
form
'
))
.
on
(
'
change
'
,
false
,
false
,
$
.
proxy
(
this
.
updateSignature
,
this
))
.
on
(
'
change
'
,
false
,
false
,
$
.
proxy
(
this
.
updateSignature
,
this
))
;
// Expand on hover
// Expand on hover
var
outer
=
this
.
$signatureBox
,
var
outer
=
this
.
$signatureBox
,
inner
=
$
(
'
.inner
'
,
this
.
$signatureBox
).
get
(
0
),
inner
=
$
(
'
.inner
'
,
this
.
$signatureBox
).
get
(
0
),
...
@@ -181,14 +171,14 @@ RedactorPlugins.signature = {
...
@@ -181,14 +171,14 @@ RedactorPlugins.signature = {
url
+=
'
dept/
'
+
$el
.
data
(
'
deptId
'
);
url
+=
'
dept/
'
+
$el
.
data
(
'
deptId
'
);
else
if
(
selected
==
'
dept
'
&&
$el
.
data
(
'
deptField
'
))
{
else
if
(
selected
==
'
dept
'
&&
$el
.
data
(
'
deptField
'
))
{
if
(
dept
)
if
(
dept
)
url
+=
'
dept/
'
+
dept
url
+=
'
dept/
'
+
dept
;
else
else
return
inner
.
empty
().
parent
().
hide
();
return
inner
.
empty
().
parent
().
hide
();
}
}
else
if
(
type
==
'
none
'
)
else
if
(
type
==
'
none
'
)
return
inner
.
empty
().
parent
().
hide
();
return
inner
.
empty
().
parent
().
hide
();
else
else
url
+=
selected
url
+=
selected
;
inner
.
load
(
url
).
parent
().
show
();
inner
.
load
(
url
).
parent
().
show
();
}
}
...
@@ -206,10 +196,6 @@ $(function() {
...
@@ -206,10 +196,6 @@ $(function() {
.
attr
(
'
height
'
,
img
.
clientHeight
);
.
attr
(
'
height
'
,
img
.
clientHeight
);
html
=
html
.
replace
(
before
,
img
.
outerHTML
);
html
=
html
.
replace
(
before
,
img
.
outerHTML
);
});
});
// Drop <inline> elements if found in the text (shady mojo happening
// inside the Redactor editor)
// DELME: When this is fixed upstream in Redactor
html
=
html
.
replace
(
/<inline /
,
'
<span
'
).
replace
(
/<
\/
inline>/
,
'
</span>
'
);
return
html
;
return
html
;
},
},
redact
=
$
.
redact
=
function
(
el
,
options
)
{
redact
=
$
.
redact
=
function
(
el
,
options
)
{
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment