diff --git a/acf-code-editor-v5.php b/acf-code-editor-v5.php new file mode 100644 index 0000000..4576cf1 --- /dev/null +++ b/acf-code-editor-v5.php @@ -0,0 +1,522 @@ +name = 'acf_code_editor'; + + + /* + * label (string) Multiple words, can include spaces, visible when selecting a field type + */ + + $this->label = __( 'Code editor field', 'acf-code-editor' ); + + + /* + * category (string) basic | content | choice | relational | jquery | layout | CUSTOM GROUP NAME + */ + + $this->category = 'Code tools'; + + + /* + * defaults (array) Array of default settings which are merged into the field object. These are used later in settings + */ + + $this->defaults = array( + ); + + + + // do not delete! + parent::__construct(); + + } + + + /* + * render_field_settings() + * + * Create extra settings for your field. These are visible when editing a field + * + * + * @param $field (array) the $field being edited + * @return n/a + */ + + function render_field_settings( $field ) { + + /* + * acf_render_field_setting + * + * This function will create a setting for your field. Simply pass the $field parameter and an array of field settings. + * The array of settings does not require a `value` or `prefix`; These settings are found from the $field array. + * + * More than one setting can be added by copy/paste the above code. + * Please note that you must also have a matching $defaults value for the field name (font_size) + */ + + + + } + + + /* + * render_field() + * + * Create the HTML interface for your field + * + * @param $field (array) the $field being rendered + * + * @type action + * @since 3.6 + * + * @param $field (array) the $field being edited + * @return n/a + */ + + function render_field( $field ) { + $dir = plugin_dir_url( __FILE__ ); + $safe_slug = str_replace( "-", "_", $field[ 'id' ] ); + // vars + $o = array( 'id', 'class', 'name'); + $e = ''; + // populate atts + $atts = array(); + foreach( $o as $k ) { + $atts[ $k ] = $field[ $k ]; + } + $e .= '
'; + // return + echo $e; + } + + + /* + * input_admin_enqueue_scripts() + * + * This action is called in the admin_enqueue_scripts action on the edit screen where your field is created. + * Use this action to add CSS + JavaScript to assist your render_field() action. + * + * @type action (admin_enqueue_scripts) + * @since 3.6 + * @date 23/01/13 + * + * @param n/a + * @return n/a + */ + + /* + + */ + + function input_admin_enqueue_scripts() { + + $dir = plugin_dir_url( __FILE__ ); + $dir = WPMU_PLUGIN_DIR; + $dir = explode('/', $dir); + $last = array_pop($dir); + $next_last = array_pop($dir); + $folder = basename(dirname(__FILE__)); + $base_url = get_bloginfo('url'); + $dir = "$base_url/$next_last/$last/$folder/"; + + + + // register & include JS + wp_register_script( 'acf-input-code_editor-custom', "{$dir}js/custom-js.js" ); + wp_enqueue_script('acf-input-code_editor-custom'); + + // register & include CSS + wp_enqueue_style( 'acf-input-code-field', "{$dir}css/codemirror.css" ); + wp_enqueue_style( 'codemirror-monokai', "{$dir}css/monokai.css" ); + + + } + + + /* + * input_admin_head() + * + * This action is called in the admin_head action on the edit screen where your field is created. + * Use this action to add CSS and JavaScript to assist your render_field() action. + * + * @type action (admin_head) + * @since 3.6 + * @date 23/01/13 + * + * @param n/a + * @return n/a + */ + + /* + + function input_admin_head() { + + + + } + + */ + + + /* + * input_form_data() + * + * This function is called once on the 'input' page between the head and footer + * There are 2 situations where ACF did not load during the 'acf/input_admin_enqueue_scripts' and + * 'acf/input_admin_head' actions because ACF did not know it was going to be used. These situations are + * seen on comments / user edit forms on the front end. This function will always be called, and includes + * $args that related to the current screen such as $args['post_id'] + * + * @type function + * @date 6/03/2014 + * @since 5.0.0 + * + * @param $args (array) + * @return n/a + */ + + /* + + function input_form_data( $args ) { + + + + } + + */ + + + /* + * input_admin_footer() + * + * This action is called in the admin_footer action on the edit screen where your field is created. + * Use this action to add CSS and JavaScript to assist your render_field() action. + * + * @type action (admin_footer) + * @since 3.6 + * @date 23/01/13 + * + * @param n/a + * @return n/a + */ + + /* + + function input_admin_footer() { + + + + } + + */ + + + /* + * field_group_admin_enqueue_scripts() + * + * This action is called in the admin_enqueue_scripts action on the edit screen where your field is edited. + * Use this action to add CSS + JavaScript to assist your render_field_options() action. + * + * @type action (admin_enqueue_scripts) + * @since 3.6 + * @date 23/01/13 + * + * @param n/a + * @return n/a + */ + + /* + + function field_group_admin_enqueue_scripts() { + + } + + */ + + + /* + * field_group_admin_head() + * + * This action is called in the admin_head action on the edit screen where your field is edited. + * Use this action to add CSS and JavaScript to assist your render_field_options() action. + * + * @type action (admin_head) + * @since 3.6 + * @date 23/01/13 + * + * @param n/a + * @return n/a + */ + + /* + + function field_group_admin_head() { + + } + + */ + + + /* + * load_value() + * + * This filter is applied to the $value after it is loaded from the db + * + * @type filter + * @since 3.6 + * @date 23/01/13 + * + * @param $value (mixed) the value found in the database + * @param $post_id (mixed) the $post_id from which the value was loaded + * @param $field (array) the field array holding all the field options + * @return $value + */ + + /* + + function load_value( $value, $post_id, $field ) { + + return $value; + + } + + */ + + + /* + * update_value() + * + * This filter is applied to the $value before it is saved in the db + * + * @type filter + * @since 3.6 + * @date 23/01/13 + * + * @param $value (mixed) the value found in the database + * @param $post_id (mixed) the $post_id from which the value was loaded + * @param $field (array) the field array holding all the field options + * @return $value + */ + + /* + + function update_value( $value, $post_id, $field ) { + + return $value; + + } + + */ + + + /* + * format_value() + * + * This filter is appied to the $value after it is loaded from the db and before it is returned to the template + * + * @type filter + * @since 3.6 + * @date 23/01/13 + * + * @param $value (mixed) the value which was loaded from the database + * @param $post_id (mixed) the $post_id from which the value was loaded + * @param $field (array) the field array holding all the field options + * + * @return $value (mixed) the modified value + */ + + /* + + function format_value( $value, $post_id, $field ) { + + // bail early if no value + if( empty($value) ) { + + return $value; + + } + + + // apply setting + if( $field['font_size'] > 12 ) { + + // format the value + // $value = 'something'; + + } + + + // return + return $value; + } + + */ + + + /* + * validate_value() + * + * This filter is used to perform validation on the value prior to saving. + * All values are validated regardless of the field's required setting. This allows you to validate and return + * messages to the user if the value is not correct + * + * @type filter + * @date 11/02/2014 + * @since 5.0.0 + * + * @param $valid (boolean) validation status based on the value and the field's required setting + * @param $value (mixed) the $_POST value + * @param $field (array) the field array holding all the field options + * @param $input (string) the corresponding input name for $_POST value + * @return $valid + */ + + /* + + function validate_value( $valid, $value, $field, $input ){ + + // Basic usage + if( $value < $field['custom_minimum_setting'] ) + { + $valid = false; + } + // Advanced usage + if( $value < $field['custom_minimum_setting'] ) + { + $valid = __('The value is too little!','acf-FIELD_NAME'), + } + // return + return $valid; + + } + + */ + + + /* + * delete_value() + * + * This action is fired after a value has been deleted from the db. + * Please note that saving a blank value is treated as an update, not a delete + * + * @type action + * @date 6/03/2014 + * @since 5.0.0 + * + * @param $post_id (mixed) the $post_id from which the value was deleted + * @param $key (string) the $meta_key which the value was deleted + * @return n/a + */ + + /* + + function delete_value( $post_id, $key ) { + + + + } + + */ + + + /* + * load_field() + * + * This filter is applied to the $field after it is loaded from the database + * + * @type filter + * @date 23/01/2013 + * @since 3.6.0 + * + * @param $field (array) the field array holding all the field options + * @return $field + */ + + /* + + function load_field( $field ) { + + return $field; + + } + + */ + + + /* + * update_field() + * + * This filter is applied to the $field before it is saved to the database + * + * @type filter + * @date 23/01/2013 + * @since 3.6.0 + * + * @param $field (array) the field array holding all the field options + * @return $field + */ + + /* + + function update_field( $field ) { + + return $field; + + } + + */ + + + /* + * delete_field() + * + * This action is fired after a field is deleted from the database + * + * @type action + * @date 11/02/2014 + * @since 5.0.0 + * + * @param $field (array) the field array holding all the field options + * @return n/a + */ + + /* + + function delete_field( $field ) { + + + + } + + */ + +} + + +// create field +new acf_code_field(); + +?> diff --git a/acf-code-editor.php b/acf-code-editor.php new file mode 100644 index 0000000..adc1435 --- /dev/null +++ b/acf-code-editor.php @@ -0,0 +1,36 @@ + diff --git a/css/codemirror.css b/css/codemirror.css new file mode 100644 index 0000000..bdf790b --- /dev/null +++ b/css/codemirror.css @@ -0,0 +1,342 @@ +/* BASICS */ + +.CodeMirror { + /* Set height, width, borders, and global font properties here */ + font-family: monospace; + height: 300px; + color: black; +} + +.CodeMirror + .CodeMirror { + display: none; +} + +/* PADDING */ + +.CodeMirror-lines { + padding: 4px 0; /* Vertical padding around content */ +} +.CodeMirror pre { + padding: 0 4px; /* Horizontal padding of content */ +} + +.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + background-color: white; /* The little square between H and V scrollbars */ +} + +/* GUTTER */ + +.CodeMirror-gutters { + border-right: 1px solid #ddd; + background-color: #f7f7f7; + white-space: nowrap; +} +.CodeMirror-linenumbers {} +.CodeMirror-linenumber { + padding: 0 3px 0 5px; + min-width: 20px; + text-align: right; + color: #999; + white-space: nowrap; +} + +.CodeMirror-guttermarker { color: black; } +.CodeMirror-guttermarker-subtle { color: #999; } + +/* CURSOR */ + +.CodeMirror-cursor { + border-left: 1px solid black; + border-right: none; + width: 0; +} +/* Shown when moving in bi-directional text */ +.CodeMirror div.CodeMirror-secondarycursor { + border-left: 1px solid silver; +} +.cm-fat-cursor .CodeMirror-cursor { + width: auto; + border: 0 !important; + background: #7e7; +} +.cm-fat-cursor div.CodeMirror-cursors { + z-index: 1; +} + +.cm-animate-fat-cursor { + width: auto; + border: 0; + -webkit-animation: blink 1.06s steps(1) infinite; + -moz-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; + background-color: #7e7; +} +@-moz-keyframes blink { + 0% {} + 50% { background-color: transparent; } + 100% {} +} +@-webkit-keyframes blink { + 0% {} + 50% { background-color: transparent; } + 100% {} +} +@keyframes blink { + 0% {} + 50% { background-color: transparent; } + 100% {} +} + +/* Can style cursor different in overwrite (non-insert) mode */ +.CodeMirror-overwrite .CodeMirror-cursor {} + +.cm-tab { display: inline-block; text-decoration: inherit; } + +.CodeMirror-ruler { + border-left: 1px solid #ccc; + position: absolute; +} + +/* DEFAULT THEME */ + +.cm-s-default .cm-header {color: blue;} +.cm-s-default .cm-quote {color: #090;} +.cm-negative {color: #d44;} +.cm-positive {color: #292;} +.cm-header, .cm-strong {font-weight: bold;} +.cm-em {font-style: italic;} +.cm-link {text-decoration: underline;} +.cm-strikethrough {text-decoration: line-through;} + +.cm-s-default .cm-keyword {color: #708;} +.cm-s-default .cm-atom {color: #219;} +.cm-s-default .cm-number {color: #164;} +.cm-s-default .cm-def {color: #00f;} +.cm-s-default .cm-variable, +.cm-s-default .cm-punctuation, +.cm-s-default .cm-property, +.cm-s-default .cm-operator {} +.cm-s-default .cm-variable-2 {color: #05a;} +.cm-s-default .cm-variable-3 {color: #085;} +.cm-s-default .cm-comment {color: #a50;} +.cm-s-default .cm-string {color: #a11;} +.cm-s-default .cm-string-2 {color: #f50;} +.cm-s-default .cm-meta {color: #555;} +.cm-s-default .cm-qualifier {color: #555;} +.cm-s-default .cm-builtin {color: #30a;} +.cm-s-default .cm-bracket {color: #997;} +.cm-s-default .cm-tag {color: #170;} +.cm-s-default .cm-attribute {color: #00c;} +.cm-s-default .cm-hr {color: #999;} +.cm-s-default .cm-link {color: #00c;} + +.cm-s-default .cm-error {color: #f00;} +.cm-invalidchar {color: #f00;} + +.CodeMirror-composing { border-bottom: 2px solid; } + +/* Default styles for common addons */ + +div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} +div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} +.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } +.CodeMirror-activeline-background {background: #e8f2ff;} + +/* STOP */ + +/* The rest of this file contains styles related to the mechanics of + the editor. You probably shouldn't touch them. */ + +.CodeMirror { + position: relative; + overflow: hidden; + background: white; +} + +.CodeMirror-scroll { + overflow: scroll !important; /* Things will break if this is overridden */ + /* 30px is the magic margin used to hide the element's real scrollbars */ + /* See overflow: hidden in .CodeMirror */ + margin-bottom: -30px; margin-right: -30px; + padding-bottom: 30px; + height: 100%; + outline: none; /* Prevent dragging from highlighting the element */ + position: relative; +} +.CodeMirror-sizer { + position: relative; + border-right: 30px solid transparent; +} + +/* The fake, visible scrollbars. Used to force redraw during scrolling + before actual scrolling happens, thus preventing shaking and + flickering artifacts. */ +.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + position: absolute; + z-index: 6; + display: none; +} +.CodeMirror-vscrollbar { + right: 0; top: 0; + overflow-x: hidden; + overflow-y: scroll; +} +.CodeMirror-hscrollbar { + bottom: 0; left: 0; + overflow-y: hidden; + overflow-x: scroll; +} +.CodeMirror-scrollbar-filler { + right: 0; bottom: 0; +} +.CodeMirror-gutter-filler { + left: 0; bottom: 0; +} + +.CodeMirror-gutters { + position: absolute; left: 0; top: 0; + min-height: 100%; + z-index: 3; +} +.CodeMirror-gutter { + white-space: normal; + height: 100%; + display: inline-block; + vertical-align: top; + margin-bottom: -30px; + /* Hack to make IE7 behave */ + *zoom:1; + *display:inline; +} +.CodeMirror-gutter-wrapper { + position: absolute; + z-index: 4; + background: none !important; + border: none !important; +} +.CodeMirror-gutter-background { + position: absolute; + top: 0; bottom: 0; + z-index: 4; +} +.CodeMirror-gutter-elt { + position: absolute; + cursor: default; + z-index: 4; +} +.CodeMirror-gutter-wrapper { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.CodeMirror-lines { + cursor: text; + min-height: 1px; /* prevents collapsing before first draw */ +} +.CodeMirror pre { + /* Reset some styles that the rest of the page might have set */ + -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; + border-width: 0; + background: transparent; + font-family: inherit; + font-size: inherit; + margin: 0; + white-space: pre; + word-wrap: normal; + line-height: inherit; + color: inherit; + z-index: 2; + position: relative; + overflow: visible; + -webkit-tap-highlight-color: transparent; + -webkit-font-variant-ligatures: none; + font-variant-ligatures: none; +} +.CodeMirror-wrap pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: normal; +} + +.CodeMirror-linebackground { + position: absolute; + left: 0; right: 0; top: 0; bottom: 0; + z-index: 0; +} + +.CodeMirror-linewidget { + position: relative; + z-index: 2; + overflow: auto; +} + +.CodeMirror-widget {} + +.CodeMirror-code { + outline: none; +} + +/* Force content-box sizing for the elements where we expect it */ +.CodeMirror-scroll, +.CodeMirror-sizer, +.CodeMirror-gutter, +.CodeMirror-gutters, +.CodeMirror-linenumber { + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +.CodeMirror-measure { + position: absolute; + width: 100%; + height: 0; + overflow: hidden; + visibility: hidden; +} + +.CodeMirror-cursor { position: absolute; } +.CodeMirror-measure pre { position: static; } + +div.CodeMirror-cursors { + visibility: hidden; + position: relative; + z-index: 3; +} +div.CodeMirror-dragcursors { + visibility: visible; +} + +.CodeMirror-focused div.CodeMirror-cursors { + visibility: visible; +} + +.CodeMirror-selected { background: #d9d9d9; } +.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } +.CodeMirror-crosshair { cursor: crosshair; } +.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; } +.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; } + +.cm-searching { + background: #ffa; + background: rgba(255, 255, 0, .4); +} + +/* IE7 hack to prevent it from returning funny offsetTops on the spans */ +.CodeMirror span { *vertical-align: text-bottom; } + +/* Used to force a border model for a node */ +.cm-force-border { padding-right: .1px; } + +@media print { + /* Hide the cursor when printing */ + .CodeMirror div.CodeMirror-cursors { + visibility: hidden; + } +} + +/* See issue #2901 */ +.cm-tab-wrap-hack:after { content: ''; } + +/* Help users use markselection to safely style text background */ +span.CodeMirror-selectedtext { background: none; } diff --git a/css/monokai.css b/css/monokai.css new file mode 100644 index 0000000..7c8a4c5 --- /dev/null +++ b/css/monokai.css @@ -0,0 +1,36 @@ +/* Based on Sublime Text's Monokai theme */ + +.cm-s-monokai.CodeMirror { background: #272822; color: #f8f8f2; } +.cm-s-monokai div.CodeMirror-selected { background: #49483E; } +.cm-s-monokai .CodeMirror-line::selection, .cm-s-monokai .CodeMirror-line > span::selection, .cm-s-monokai .CodeMirror-line > span > span::selection { background: rgba(73, 72, 62, .99); } +.cm-s-monokai .CodeMirror-line::-moz-selection, .cm-s-monokai .CodeMirror-line > span::-moz-selection, .cm-s-monokai .CodeMirror-line > span > span::-moz-selection { background: rgba(73, 72, 62, .99); } +.cm-s-monokai .CodeMirror-gutters { background: #272822; border-right: 0px; } +.cm-s-monokai .CodeMirror-guttermarker { color: white; } +.cm-s-monokai .CodeMirror-guttermarker-subtle { color: #d0d0d0; } +.cm-s-monokai .CodeMirror-linenumber { color: #d0d0d0; } +.cm-s-monokai .CodeMirror-cursor { border-left: 1px solid #f8f8f0; } + +.cm-s-monokai span.cm-comment { color: #75715e; } +.cm-s-monokai span.cm-atom { color: #ae81ff; } +.cm-s-monokai span.cm-number { color: #ae81ff; } + +.cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute { color: #a6e22e; } +.cm-s-monokai span.cm-keyword { color: #f92672; } +.cm-s-monokai span.cm-builtin { color: #66d9ef; } +.cm-s-monokai span.cm-string { color: #e6db74; } + +.cm-s-monokai span.cm-variable { color: #f8f8f2; } +.cm-s-monokai span.cm-variable-2 { color: #9effff; } +.cm-s-monokai span.cm-variable-3 { color: #66d9ef; } +.cm-s-monokai span.cm-def { color: #fd971f; } +.cm-s-monokai span.cm-bracket { color: #f8f8f2; } +.cm-s-monokai span.cm-tag { color: #f92672; } +.cm-s-monokai span.cm-header { color: #ae81ff; } +.cm-s-monokai span.cm-link { color: #ae81ff; } +.cm-s-monokai span.cm-error { background: #f92672; color: #f8f8f0; } + +.cm-s-monokai .CodeMirror-activeline-background { background: #373831; } +.cm-s-monokai .CodeMirror-matchingbracket { + text-decoration: underline; + color: white !important; +} diff --git a/js/custom-js.js b/js/custom-js.js index a5a1262..0a68021 100644 --- a/js/custom-js.js +++ b/js/custom-js.js @@ -11046,8 +11046,48 @@ require('codemirror/mode/css/css'); require('codemirror/mode/htmlmixed/htmlmixed'); -require('codemirror/lib/codemirror'); +var CodeMirror = require('codemirror/lib/codemirror'); -console.log(CodeMirror); +window.$ = window.$ || jQuery || window.jQuery; + +var sw_interval = void 0; + +var instantiator = function instantiator(el) { + var instance = CodeMirror.fromTextArea(el, { + lineNumbers: true, + mode: "htmlmixed", + theme: 'monokai', + tabSize: 2, + lineWrapping: true + }); + return instance; +}; + +var strict_wysiwyg = function strict_wysiwyg() { + console.log('Interval fired'); + if (typeof $ !== "undefined" && $ !== null) { + clearInterval(sw_interval); + var editors = $('.codemirror-wrapper textarea'); + if (editors.length) { + for (var i = 0; i < editors.length; i++) { + instantiator(editors[i]); + } + } + } +}; + +acf.add_action('ready', function () { + sw_interval = setInterval(strict_wysiwyg, 10); +}); + +acf.add_action('append', function ($el) { + // $el will be equivalent to the new element being appended $('tr.row') + // find a specific field + var $field = $el.find('.codemirror-wrapper textarea'); + if ($field.length) { + var newInstance = instantiator($field[0]); + newInstance.focus(); + } +}); },{"codemirror/lib/codemirror":1,"codemirror/mode/css/css":2,"codemirror/mode/htmlmixed/htmlmixed":3,"codemirror/mode/javascript/javascript":4,"codemirror/mode/xml/xml":5}]},{},[6]); diff --git a/src/main.js b/src/main.js index 71edf96..9b4abbd 100644 --- a/src/main.js +++ b/src/main.js @@ -3,6 +3,46 @@ import 'codemirror/mode/javascript/javascript' import 'codemirror/mode/css/css' import 'codemirror/mode/htmlmixed/htmlmixed' -import 'codemirror/lib/codemirror' +var CodeMirror = require('codemirror/lib/codemirror') -console.log(CodeMirror) +window.$ = window.$ || jQuery || window.jQuery + +let sw_interval + +let instantiator = function(el) { + let instance = CodeMirror.fromTextArea(el, { + lineNumbers: true, + mode: "htmlmixed", + theme: 'monokai', + tabSize: 2, + lineWrapping: true + }) + return instance +} + +const strict_wysiwyg = function() { + console.log('Interval fired') + if ((typeof $ !== "undefined" && $ !== null)) { + clearInterval(sw_interval) + var editors = $('.codemirror-wrapper textarea') + if (editors.length) { + for (var i=0;i < editors.length; i++) { + instantiator(editors[i]) + } + } + } +} + +acf.add_action('ready', function() { + sw_interval = setInterval(strict_wysiwyg, 10); +}); + +acf.add_action('append', ( $el ) => { + // $el will be equivalent to the new element being appended $('tr.row') + // find a specific field + let $field = $el.find('.codemirror-wrapper textarea') + if ($field.length) { + let newInstance = instantiator($field[0]) + newInstance.focus() + } +})