From bac02aa99edd26c859a7b5fd42eb08bcbb175b80 Mon Sep 17 00:00:00 2001 From: Shady Sharaf Date: Sat, 1 Feb 2014 22:56:37 +0200 Subject: [PATCH 1/2] Use WordPress's way of doing metaboxes, sortables/closables/layout-columns --- includes/form.php | 332 +++++++++++++++++++++++++++++++++++++++ stream-notifications.php | 261 ++---------------------------- views/rule-form.php | 97 +----------- 3 files changed, 350 insertions(+), 340 deletions(-) create mode 100644 includes/form.php diff --git a/includes/form.php b/includes/form.php new file mode 100644 index 000000000..271629378 --- /dev/null +++ b/includes/form.php @@ -0,0 +1,332 @@ + 2, 'default' => 2 ) ); + + // Register metaboxes + add_meta_box( + 'triggers', + __( 'Triggers', 'stream-notifications' ), + array( $this, 'metabox_triggers' ), + WP_Stream_Notifications::$screen_id, + 'normal' + ); + add_meta_box( + 'alerts', + __( 'Alerts', 'stream-notifications' ), + array( $this, 'metabox_alerts' ), + WP_Stream_Notifications::$screen_id, + 'normal' + ); + add_meta_box( + 'submitdiv', + __( 'Save', 'stream-notifications' ), + array( $this, 'metabox_save' ), + WP_Stream_Notifications::$screen_id, + 'side' + ); + } + + /** + * Enqueue our scripts, in our own page only + * + * @action admin_enqueue_scripts + * @param string $hook Current admin page slug + * @return void + */ + public function enqueue_scripts( $hook ) { + if ( + $hook != WP_Stream_Notifications::$screen_id + || + filter_input( INPUT_GET, 'view' ) != 'rule' + ) { + return; + } + + $view = filter_input( INPUT_GET, 'view', FILTER_DEFAULT, array( 'options' => array( 'default' => 'list' ) ) ); + + if ( $view == 'rule' ) { + wp_enqueue_script( 'dashboard' ); + wp_enqueue_style( 'select2' ); + wp_enqueue_script( 'select2' ); + wp_enqueue_script( 'underscore' ); + wp_enqueue_script( 'stream-notifications-main', WP_STREAM_NOTIFICATIONS_URL . '/ui/js/main.js', array( 'underscore', 'select2' ) ); + wp_localize_script( 'stream-notifications-main', 'stream_notifications', $this->get_js_options() ); + } + } + + + /** + * Callback for form AJAX operations + * + * @action wp_ajax_stream_notifications_endpoint + * @return void + */ + public function form_ajax_ep() { + // BIG @TODO: Make the request context-aware, + // ie: get other rules ( maybe in the same group only ? ), so an author + // query would check if there is a author_role rule available to limit + // the results according to it + + $type = filter_input( INPUT_POST, 'type' ); + $is_single = filter_input( INPUT_POST, 'single' ); + $query = filter_input( INPUT_POST, 'q' ); + + if ( $is_single ) { + switch ( $type ) { + case 'author': + $user_ids = explode( ',', $query ); + $user_query = new WP_User_Query( + array( + 'include' => $user_ids, + 'fields' => array( 'ID', 'user_email', 'display_name' ), + ) + ); + if ( $user_query->results ) { + $data = $this->format_json_for_select2( + $user_query->results, + 'ID', + 'display_name' + ); + } else { + $data = array(); + } + break; + case 'action': + $actions = WP_Stream_Connectors::$term_labels['stream_action']; + $values = explode( ',', $query ); + $actions = array_intersect_key( $actions, array_flip( $values ) ); + $data = $this->format_json_for_select2( $actions ); + break; + } + } else { + switch ( $type ) { + case 'author': + $users = get_users( array( 'search' => '*' . $query . '*' ) ); + $data = $this->format_json_for_select2( $users, 'ID', 'display_name' ); + break; + case 'action': + $actions = WP_Stream_Connectors::$term_labels['stream_action']; + $actions = preg_grep( sprintf( '/%s/i', $query ), $actions ); + $data = $this->format_json_for_select2( $actions ); + break; + } + } + if ( isset( $data ) ) { + wp_send_json_success( $data ); + } else { + wp_send_json_error(); + } + } + + /** + * Take an (associative) array and format it for select2 AJAX result parser + * @param array $data (associative) Data array + * @param string $key Key of the ID column, null if associative array + * @param string $val Key of the Title column, null if associative array + * @return array Formatted array, [ { id: %, title: % }, .. ] + */ + public function format_json_for_select2( $data, $key = null, $val = null ) { + $return = array(); + if ( is_null( $key ) && is_null( $val ) ) { // for flat associative array + $keys = array_keys( $data ); + $vals = array_values( $data ); + } else { + $keys = wp_list_pluck( $data, $key ); + $vals = wp_list_pluck( $data, $val ); + } + foreach ( $keys as $idx => $key ) { + $return[] = array( + 'id' => $key, + 'text' => $vals[$idx], + ); + } + return $return; + } + + /** + * Format JS options for the form, to be used with wp_localize_script + * + * @return array Options for our form JS handling + */ + public function get_js_options() { + global $wp_roles; + $args = array(); + + $roles = $wp_roles->roles; + $roles_arr = array_combine( array_keys( $roles ), wp_list_pluck( $roles, 'name' ) ); + + $default_operators = array( + '=' => __( 'is', 'stream-notifications' ), + '!=' => __( 'is not', 'stream-notifications' ), + 'in' => __( 'in', 'stream-notifications' ), + '!in' => __( 'not in', 'stream-notifications' ), + ); + + $args['types'] = array( + 'search' => array( + 'title' => __( 'Summary', 'stream-notifications' ), + 'type' => 'text', + 'operators' => array( + '=' => __( 'is', 'stream-notifications' ), + '!=' => __( 'is not', 'stream-notifications' ), + 'contains' => __( 'contains', 'stream-notifications' ), + '!contains' => __( 'does not contain', 'stream-notifications' ), + 'regex' => __( 'regex', 'stream-notifications' ), + ), + ), + 'object_id' => array( + 'title' => __( 'Object ID', 'stream-notifications' ), + 'type' => 'text', + 'tags' => true, + 'operators' => $default_operators, + ), + + 'author_role' => array( + 'title' => __( 'Author Role', 'stream-notifications' ), + 'type' => 'select', + 'multiple' => true, + 'operators' => $default_operators, + 'options' => $roles_arr, + ), + + 'author' => array( + 'title' => __( 'Author', 'stream-notifications' ), + 'type' => 'text', + 'ajax' => true, + 'operators' => $default_operators, + ), + + 'ip' => array( + 'title' => __( 'IP', 'stream-notifications' ), + 'type' => 'text', + 'tags' => true, + 'operators' => $default_operators, + ), + + 'date' => array( + 'title' => __( 'Date', 'stream-notifications' ), + 'type' => 'date', + 'operators' => array( + '=' => __( 'is on', 'stream-notifications' ), + '!=' => __( 'is not on', 'stream-notifications' ), + '<' => __( 'is before', 'stream-notifications' ), + '<=' => __( 'is on or before', 'stream-notifications' ), + '>' => __( 'is after', 'stream-notifications' ), + '>=' => __( 'is on or after', 'stream-notifications' ), + ), + ), + + // TODO: find a way to introduce meta to the rules, problem: not translatable since it is + // generated on run time with no prior definition + // 'meta_query' => array(), + + 'connector' => array( + 'title' => __( 'Connector', 'stream-notifications' ), + 'type' => 'select', + 'operators' => $default_operators, + 'options' => WP_Stream_Connectors::$term_labels['stream_connector'], + ), + 'context' => array( + 'title' => __( 'Context', 'stream-notifications' ), + 'type' => 'text', + 'ajax' => true, + 'operators' => $default_operators, + ), + 'action' => array( + 'title' => __( 'Action', 'stream-notifications' ), + 'type' => 'text', + 'ajax' => true, + 'operators' => $default_operators, + ), + ); + + $args['adapters'] = array(); + + foreach ( WP_Stream_Notifications::$adapters as $name => $options ) { + $args['adapters'][$name] = array( + 'title' => $options['title'], + 'fields' => $options['class']::fields(), + ); + } + + // Localization + $args['i18n'] = array( + 'empty_triggers' => __( 'A rule must contain at least one trigger to be saved.', 'stream-notifications' ), + ); + + return apply_filters( 'stream_notification_js_args', $args ); + } + + public function metabox_triggers() { + ?> + + +
+ + + +
+
+
+
+ +
+
+
+ +
+ exists() ) : ?> +
+ WP_Stream_Notifications::NOTIFICATIONS_PAGE_SLUG, + 'action' => 'delete', + 'id' => absint( $rule->ID ), + 'wp_stream_nonce' => wp_create_nonce( 'delete-record_' . absint( $rule->ID ) ), + ), + admin_url( WP_Stream_Admin::ADMIN_PARENT_PAGE ) + ); + ?> + + + +
+ + +
+ + +
+
+
+
+ matcher = new WP_Stream_Notification_Rule_Matcher(); + + // Load form class + + if ( is_admin() ) { + include WP_STREAM_NOTIFICATIONS_INC_DIR . '/form.php'; + $this->form = new WP_Stream_Notifications_Form; + } } /** @@ -155,30 +164,7 @@ public function register_menu() { ); add_action( 'load-' . self::$screen_id, array( $this, 'page_form_save' ) ); - } - - /** - * Enqueue our scripts, in our own page only - * - * @action admin_enqueue_scripts - * @param string $hook Current admin page slug - * @return void - */ - public function enqueue_scripts( $hook ) { - if ( $hook != self::$screen_id ) { - return; - } - - $view = filter_input( INPUT_GET, 'view', FILTER_DEFAULT, array( 'options' => array( 'default' => 'list' ) ) ); - - if ( $view == 'rule' ) { - wp_enqueue_script( 'dashboard' ); - wp_enqueue_style( 'select2' ); - wp_enqueue_script( 'select2' ); - wp_enqueue_script( 'underscore' ); - wp_enqueue_script( 'stream-notifications-main', WP_STREAM_NOTIFICATIONS_URL . '/ui/js/main.js', array( 'underscore', 'select2' ) ); - wp_localize_script( 'stream-notifications-main', 'stream_notifications', $this->get_js_options() ); - } + add_action( 'load-' . self::$screen_id, array( $this->form, 'load' ) ); } public static function register_adapter( $adapter, $name, $title ) { @@ -188,137 +174,6 @@ public static function register_adapter( $adapter, $name, $title ) { ); } - /** - * Format JS options for the form, to be used with wp_localize_script - * - * @return array Options for our form JS handling - */ - public function get_js_options() { - global $wp_roles; - $args = array(); - - $roles = $wp_roles->roles; - $roles_arr = array_combine( array_keys( $roles ), wp_list_pluck( $roles, 'name' ) ); - - $default_operators = array( - '=' => __( 'is', 'stream-notifications' ), - '!=' => __( 'is not', 'stream-notifications' ), - 'in' => __( 'in', 'stream-notifications' ), - '!in' => __( 'not in', 'stream-notifications' ), - ); - - $args['types'] = array( - 'search' => array( - 'title' => __( 'Summary', 'stream-notifications' ), - 'type' => 'text', - 'operators' => array( - '=' => __( 'is', 'stream-notifications' ), - '!=' => __( 'is not', 'stream-notifications' ), - 'contains' => __( 'contains', 'stream-notifications' ), - '!contains' => __( 'does not contain', 'stream-notifications' ), - 'regex' => __( 'regex', 'stream-notifications' ), - ), - ), - // 'object_type' => array( - // 'title' => __( 'Object Type', 'stream-notifications' ), - // 'type' => 'select', - // 'multiple' => true, - // 'operators' => array( - // '=' => __( 'is', 'stream-notifications' ), - // '!=' => __( 'is not', 'stream-notifications' ), - // 'in' => __( 'in', 'stream-notifications' ), - // 'not_in' => __( 'not in', 'stream-notifications' ), - // ), - // 'options' => array( // TODO: Do we have a dynamic way to get this ?: Answer: NO, use 'Context' - // 'user' => __( 'User', 'stream-notifications' ), - // 'post' => __( 'Post', 'stream-notifications' ), - // 'comment' => __( 'Comment', 'stream-notifications' ), - // ), - // ), - - 'object_id' => array( - 'title' => __( 'Object ID', 'stream-notifications' ), - 'type' => 'text', - 'tags' => true, - 'operators' => $default_operators, - ), - - 'author_role' => array( - 'title' => __( 'Author Role', 'stream-notifications' ), - 'type' => 'select', - 'multiple' => true, - 'operators' => $default_operators, - 'options' => $roles_arr, - ), - - 'author' => array( - 'title' => __( 'Author', 'stream-notifications' ), - 'type' => 'text', - 'ajax' => true, - 'operators' => $default_operators, - ), - - 'ip' => array( - 'title' => __( 'IP', 'stream-notifications' ), - 'type' => 'text', - 'tags' => true, - 'operators' => $default_operators, - ), - - 'date' => array( - 'title' => __( 'Date', 'stream-notifications' ), - 'type' => 'date', - 'operators' => array( - '=' => __( 'is on', 'stream-notifications' ), - '!=' => __( 'is not on', 'stream-notifications' ), - '<' => __( 'is before', 'stream-notifications' ), - '<=' => __( 'is on or before', 'stream-notifications' ), - '>' => __( 'is after', 'stream-notifications' ), - '>=' => __( 'is on or after', 'stream-notifications' ), - ), - ), - - // TODO: find a way to introduce meta to the rules, problem: not translatable since it is - // generated on run time with no prior definition - // 'meta_query' => array(), - - 'connector' => array( - 'title' => __( 'Connector', 'stream-notifications' ), - 'type' => 'select', - 'operators' => $default_operators, - 'options' => WP_Stream_Connectors::$term_labels['stream_connector'], - ), - 'context' => array( - 'title' => __( 'Context', 'stream-notifications' ), - 'type' => 'text', - 'ajax' => true, - 'operators' => $default_operators, - ), - 'action' => array( - 'title' => __( 'Action', 'stream-notifications' ), - 'type' => 'text', - 'ajax' => true, - 'operators' => $default_operators, - ), - ); - - $args['adapters'] = array(); - - foreach ( self::$adapters as $name => $options ) { - $args['adapters'][$name] = array( - 'title' => $options['title'], - 'fields' => $options['class']::fields(), - ); - } - - // Localization - $args['i18n'] = array( - 'empty_triggers' => __( 'A rule must contain at least one trigger to be saved.', 'stream-notifications' ), - ); - - return apply_filters( 'stream_notification_js_args', $args ); - } - /** * Admin page callback function, redirects to each respective method based * on $_GET['view'] @@ -452,94 +307,6 @@ public function page_list() { echo ''; } - /** - * Callback for form AJAX operations - * - * @action wp_ajax_stream_notifications_endpoint - * @return void - */ - public function form_ajax_ep() { - // BIG @TODO: Make the request context-aware, - // ie: get other rules ( maybe in the same group only ? ), so an author - // query would check if there is a author_role rule available to limit - // the results according to it - - $type = filter_input( INPUT_POST, 'type' ); - $is_single = filter_input( INPUT_POST, 'single' ); - $query = filter_input( INPUT_POST, 'q' ); - - if ( $is_single ) { - switch ( $type ) { - case 'author': - $user_ids = explode( ',', $query ); - $user_query = new WP_User_Query( - array( - 'include' => $user_ids, - 'fields' => array( 'ID', 'user_email', 'display_name' ), - ) - ); - if ( $user_query->results ) { - $data = $this->format_json_for_select2( - $user_query->results, - 'ID', - 'display_name' - ); - } else { - $data = array(); - } - break; - case 'action': - $actions = WP_Stream_Connectors::$term_labels['stream_action']; - $values = explode( ',', $query ); - $actions = array_intersect_key( $actions, array_flip( $values ) ); - $data = $this->format_json_for_select2( $actions ); - break; - } - } else { - switch ( $type ) { - case 'author': - $users = get_users( array( 'search' => '*' . $query . '*' ) ); - $data = $this->format_json_for_select2( $users, 'ID', 'display_name' ); - break; - case 'action': - $actions = WP_Stream_Connectors::$term_labels['stream_action']; - $actions = preg_grep( sprintf( '/%s/i', $query ), $actions ); - $data = $this->format_json_for_select2( $actions ); - break; - } - } - if ( isset( $data ) ) { - wp_send_json_success( $data ); - } else { - wp_send_json_error(); - } - } - - /** - * Take an (associative) array and format it for select2 AJAX result parser - * @param array $data (associative) Data array - * @param string $key Key of the ID column, null if associative array - * @param string $val Key of the Title column, null if associative array - * @return array Formatted array, [ { id: %, title: % }, .. ] - */ - public function format_json_for_select2( $data, $key = null, $val = null ) { - $return = array(); - if ( is_null( $key ) && is_null( $val ) ) { // for flat associative array - $keys = array_keys( $data ); - $vals = array_values( $data ); - } else { - $keys = wp_list_pluck( $data, $key ); - $vals = wp_list_pluck( $data, $val ); - } - foreach ( $keys as $idx => $key ) { - $return[] = array( - 'id' => $key, - 'text' => $vals[$idx], - ); - } - return $return; - } - /* * Handle the rule activation & deactivation action */ diff --git a/views/rule-form.php b/views/rule-form.php index 8b12a7bc1..10334ca65 100644 --- a/views/rule-form.php +++ b/views/rule-form.php @@ -20,10 +20,11 @@
-
+
@@ -34,101 +35,11 @@
-
-
-

- -

-
-
-
-
-
- -
-
-
- -
- exists() ) : ?> -
- WP_Stream_Notifications::NOTIFICATIONS_PAGE_SLUG, - 'action' => 'delete', - 'id' => absint( $rule->ID ), - 'wp_stream_nonce' => wp_create_nonce( 'delete-record_' . absint( $rule->ID ) ), - ), - admin_url( WP_Stream_Admin::ADMIN_PARENT_PAGE ) - ); - ?> - - - -
- - -
- - -
-
-
-
-
-
-
+ id, 'side', $rule ); ?>
- -
- -id ); -$boxes = ( ! empty( $sortables['normal'] ) ) ? explode( ',', $sortables['normal'] ) : array( 'triggers', 'alerts' ); -foreach ( $boxes as $box ): - switch ( $box ): - case 'triggers': - ?> -
-

-

- -

-
- - - - -
- -
- -
-
- -
-

-

-
- -
-
- -
- + id, 'normal', $rule ); ?>
From e74d3133a61b938a3dd1d98a1f76b3c407030e4a Mon Sep 17 00:00:00 2001 From: Shady Sharaf Date: Sat, 1 Feb 2014 23:00:03 +0200 Subject: [PATCH 2/2] Rename js file to avoid confusion --- includes/form.php | 4 ++-- ui/js/{main.js => form.js} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename ui/js/{main.js => form.js} (100%) diff --git a/includes/form.php b/includes/form.php index 271629378..bf98980d1 100644 --- a/includes/form.php +++ b/includes/form.php @@ -63,8 +63,8 @@ public function enqueue_scripts( $hook ) { wp_enqueue_style( 'select2' ); wp_enqueue_script( 'select2' ); wp_enqueue_script( 'underscore' ); - wp_enqueue_script( 'stream-notifications-main', WP_STREAM_NOTIFICATIONS_URL . '/ui/js/main.js', array( 'underscore', 'select2' ) ); - wp_localize_script( 'stream-notifications-main', 'stream_notifications', $this->get_js_options() ); + wp_enqueue_script( 'stream-notifications-form', WP_STREAM_NOTIFICATIONS_URL . '/ui/js/form.js', array( 'underscore', 'select2' ) ); + wp_localize_script( 'stream-notifications-form', 'stream_notifications', $this->get_js_options() ); } } diff --git a/ui/js/main.js b/ui/js/form.js similarity index 100% rename from ui/js/main.js rename to ui/js/form.js