Esempio n. 1
0
/**
 * Standard tool for making payments.
 * @class Assets payment
 * @constructor
 * @param {array} $options Override various options for this tool
 *  @param {string} $options.payments can be "authnet" or "stripe"
 *  @param {string} $options.amount the amount to pay.
 *  @param {double} [$options.currency="usd"] the currency to pay in. (authnet supports only "usd")
 *  @param {string} [$options.payButton] Can override the title of the pay button
 *  @param {String} [$options.publisherId=Users::communityId()] The publisherId of the Assets/product or Assets/service stream
 *  @param {String} [$options.streamName] The name of the Assets/product or Assets/service stream
 *  @param {string} [$options.name=Users::communityName()] The name of the organization the user will be paying
 *  @param {string} [$options.image] The url pointing to a square image of your brand or product. The recommended minimum size is 128x128px.
 *  @param {string} [$options.description=null] A short name or description of the product or service being purchased.
 *  @param {string} [$options.panelLabel] The label of the payment button in the Stripe Checkout form (e.g. "Pay {{amount}}", etc.). If you include {{amount}}, it will be replaced by the provided amount. Otherwise, the amount will be appended to the end of your label.
 *  @param {string} [$options.zipCode] Specify whether Stripe Checkout should validate the billing ZIP code (true or false). The default is false.
 *  @param {boolean} [$options.billingAddress] Specify whether Stripe Checkout should collect the user's billing address (true or false). The default is false.
 *  @param {boolean} [$options.shippingAddress] Specify whether Checkout should collect the user's shipping address (true or false). The default is false.
 *  @param {string} [$options.email=Users::loggedInUser(true)->emailAddress] You can use this to override the email address, if any, provided to Stripe Checkout to be pre-filled.
 *  @param {boolean} [$options.allowRememberMe=true] Specify whether to include the option to "Remember Me" for future purchases (true or false).
 *  @param {boolean} [$options.bitcoin=false] Specify whether to accept Bitcoin (true or false). 
 *  @param {boolean} [$options.alipay=false] Specify whether to accept Alipay ('auto', true, or false). 
 *  @param {boolean} [$options.alipayReusable=false] Specify if you need reusable access to the customer's Alipay account (true or false).
 */
function Assets_payment_tool($options)
{
    Q_Valid::requireFields(array('payments', 'amount'), $options, true);
    if (empty($options['name'])) {
        $options['name'] = Users::communityName();
    }
    if (!empty($options['image'])) {
        $options['image'] = Q_Html::themedUrl($options['image']);
    }
    $options['payments'] = strtolower($options['payments']);
    if (empty($options['email'])) {
        $options['email'] = Users::loggedInUser(true)->emailAddress;
    }
    $payments = ucfirst($options['payments']);
    $currency = strtolower(Q::ifset($options, 'currency', 'usd'));
    if ($payments === 'Authnet' and $currency !== 'usd') {
        throw new Q_Exception("Authnet doesn't support currencies other than USD", 'currency');
    }
    $className = "Assets_Payments_{$payments}";
    switch ($payments) {
        case 'Authnet':
            $adapter = new $className($options);
            $token = $options['token'] = $adapter->authToken();
            $testing = $options['testing'] = Q_Config::expect('Assets', 'payments', $lcpayments, 'testing');
            $action = $options['action'] = $testing ? "https://test.authorize.net/profile/manage" : "https://secure.authorize.net/profile/manage";
            break;
        case 'Stripe':
            $publishableKey = Q_Config::expect('Assets', 'payments', 'stripe', 'publishableKey');
            break;
    }
    $titles = array('Authnet' => 'Authorize.net', 'Stripe' => 'Stripe');
    Q_Response::setToolOptions($options);
    $payButton = Q::ifset($options, 'payButton', "Pay with " . $titles[$payments]);
    return Q::view("Assets/tool/payment/{$payments}.php", compact('token', 'publishableKey', 'action', 'payButton'));
}
Esempio n. 2
0
/**
 * Renders a Websites/presentation stream,
 * including an interface to edit the presentation
 * for users who have the permissions to do so.
 * @param {array} $options
 * @param {string} $options.publisherId
 * @param {string} $options.streamName
 */
function Websites_presentation_tool($options)
{
    Q_Response::addStylesheet('plugins/Websites/css/Websites.css');
    Q_Response::addScript('plugins/Websites/js/Websites.js');
    Q_Response::setToolOptions($options);
    return '';
}
Esempio n. 3
0
/**
 * Ticker that scrolls its contents with various speeds and pauses
 * @class Q ticker
 * @constructor
 * @param {array} $options
 *  An associative array of fields, possibly including:
 *
 * "content" => string
 *  The content of the ticker. The first top-level element
 *  should contain sub-elements, and their sizes determine where
 *  the ticker would pause between automatically scrolling.
 *  The ticker animates by scrolling its inner contents.
 *
 * "vertical" => bool
 *  Defaults to true. If false, the ticker scrolls horizontally.
 *
 * "speed" => integer
 *  The scrolling speed.
 *  This is the number of items that would scroll by in 1 second,
 *  if there were no pauses.
 *  When the speed is positive, vertical tickers scroll down, and
 *  horizontal tickers scroll to the right. New content seems to come in
 *  from the bottom (for vertical tickers) or right (for horizontal tickers)
 *  as the ticker scrolls. The element inside the ticker will start out
 *  aligned with the top side of the ticker (for vertical tickers),
 *  or the left side of the ticker (for horizontal tickers).
 *  When the speed is negative, all this faces the other way.
 *
 * "pause_ms" => int
 *  Defaults to 2000. This is the number of milliseconds to wait
 *  after each second-level element of $content is automatically
 *  scrolled completely into view.
 *
 * "pause_ms_min" => int
 *  If set, then the number of milliseconds to pause is a random
 *  integer between $pause_ms_min and $pause_ms.
 *
 * "scrollbars" => bool
 *  Defaults to true. If true, shows scrollbars, otherwise doesn't.
 *  (Note: this will let the user know how much content is left,
 *   and be able to see it before it would automatically scroll into view.)
 *
 * "scrollbars_pause_ms" => int
 *  Defaults to 500. The ticker pauses its automatic scrolling when the user
 *  starts using the scrollbars. This is the number of milliseconds to wait
 *  until resuming the automatic scrolling.
 *
 * "anim_ms" => int
 *  Defaults to 100. This is the number of milliseconds between calls to
 *  autoScroll.
 *
 * "initial_scroll_mode" => string
 *  Defaults to 'auto'. This is the mode that scrolling starts out in.
 *  Possible values are 'auto' and 'paused'.
 *
 * "ease" => string
 *  Optional. If set, specifies the name of the ease function
 */
function Q_ticker_tool($options = array())
{
    $defaults = array('vertical' => true, 'speed' => 1, 'pause_ms' => 2000, 'scrollbars' => true, 'scrollbars_pause_ms' => 500, 'anim_ms' => 100);
    $fields2 = array_merge($defaults, $options);
    if (!isset($fields2['pause_ms_min'])) {
        $fields2['pause_ms_min'] = $fields2['pause_ms'];
    }
    if (!isset($fields2['content'])) {
        $li_array = array();
        for ($i = 0; $i < 100; ++$i) {
            $li_array[] = '<li><div style="background-color:#' . dechex(rand(0, 16)) . dechex(rand(0, 16)) . dechex(rand(0, 16)) . dechex(rand(0, 16)) . dechex(rand(0, 16)) . dechex(rand(0, 16)) . '">Missing $content parameter. This is just example #' . $i . '</div></li>';
        }
        $default_content = implode("\n", $li_array);
        if ($fields2['vertical']) {
            $fields2['content'] = "<ul class='error'>{$default_content}</ul>";
        } else {
            $fields2['content'] = "<ul class='error'>{$default_content}</ul>";
        }
    }
    Q_Response::addStylesheet('plugins/Q/css/ticker.css');
    Q_Response::addScript('plugins/Q/js/tools/ticker.js');
    Q_Response::setToolOptions($fields2);
    $direction_class = $fields2['vertical'] ? 'vertical' : 'horizontal';
    $scrollbars_class = $fields2['scrollbars'] ? 'scrollbars' : '';
    return Q_Html::tag('div', array('class' => "Q_ticker {$direction_class} {$scrollbars_class}"), $fields2['content']);
}
Esempio n. 4
0
/**
 * Tool for admins to edit the url, title, keywords, description of the current page
 * @class Websites seo
 * @constructor
 * @param {Object} [$options] Options for the tool
 * @param {String} [$options.skipIfNotAuthorized=true] Whether to skip rendering the contents of the tool if the logged-in user is not authorized to edit the SEO information for this page.
 */
function Websites_seo_tool($options)
{
    $skipIfNotAuthorized = Q::ifset($options, 'skipIfNotAuthorized', true);
    if ($skipIfNotAuthorized) {
        $websitesUserId = Users::communityId();
        $sha1 = sha1(Q_Dispatcher::uri());
        $seoStreamName = "Websites/seo/{$sha1}";
        $stream = Streams::fetchOne(null, $websitesUserId, $seoStreamName);
        $user = Users::loggedInUser();
        if (!$user or $stream and !$stream->testWriteLevel('suggest')) {
            $options['skip'] = true;
        }
        if (!$stream and !Streams::isAuthorizedToCreate($user->id, $websitesUserId, 'Websites/seo')) {
            $options['skip'] = true;
        }
    }
    unset($options['skipIfNotAuthorized']);
    Q_Response::addStylesheet('plugins/Websites/css/Websites.css');
    Q_Response::addScript("plugins/Websites/js/Websites.js");
    Q_Response::setToolOptions($options);
    $user = Users::loggedInUser(false, false);
    $userId = $user ? $user->id : "";
    $communityId = Users::communityId();
    $sha1 = sha1(Q_Dispatcher::uri());
    $seoStreamName = "Websites/seo/{$sha1}";
    $streams = Streams::fetch($userId, $communityId, array("Websites/header", "Websites/title", "Websites/slogan", $seoStreamName));
    foreach ($streams as $name => $s) {
        if ($s) {
            $s->addPreloaded($userId);
        }
    }
}
Esempio n. 5
0
/**
 * This tool implements expandable containers that work on most modern browsers,
 * including ones on touchscreens.
 * @class Q expandable
 * @constructor
 * @param {array} $options Options for the tool
 * @param {string} $options.title Required. The title for the expandable.
 * @param {string} $options.content The content. Required unless you pass "items" instead.
 * @param {array} [$options.items] An array of strings to wrap in <span> elements and render in the content
 * @param {string} [$options.class] If you use "items", optionally specify the class of the container elements for each item
 * @param {integer} [$options.title] A number, if any, to display when collapsed
 * @param {boolean} [$options.autoCollapseSiblings]  Whether, when expanding an expandable, its siblings should be automatically collapsed.
 */
function Q_expandable_tool($options)
{
    if (isset($options['items'])) {
        $classString = isset($options['class']) ? "class='{$options['class']}'" : '';
        $lines = array();
        foreach ($options['items'] as $key => $value) {
            $lines[] = "<span {$classString}>{$key}</span>";
        }
        $between = Q::ifset($options, 'between', '');
        $options['content'] = implode($between, $lines);
    }
    foreach (array('title', 'content') as $field) {
        if (!isset($options[$field])) {
            throw new Q_Exception_RequiredField(compact('field'));
        }
    }
    Q_Response::addScript('plugins/Q/js/tools/expandable.js');
    Q_Response::addStylesheet('plugins/Q/css/expandable.css');
    $count = Q::ifset($options, 'count', '');
    $style = empty($options['expanded']) ? '' : 'style="display:block"';
    $h2 = "<h2>\n\t<span class='Q_expandable_count'>{$count}</span>\n\t{$options['title']}\n</h2>";
    $div = "<div class='Q_expandable_container' {$style}><div class='Q_expandable_content'>\n\t{$options['content']}\n</div></div>";
    Q_Response::setToolOptions($options);
    return $h2 . $div;
}
Esempio n. 6
0
/**
 * Renders chat tool.
 * @class Streams chat
 * @constructor
 * @param {array} $options Options for the tool
 * @param {string} $options.publisherId Publisher id of the stream to get messsages from.
 * @param {string} $options.streamName Required. Name of the stream to get messsages from.
 * @param {string} [$options.loadMore] May have one these values: 'scroll', 'click' or 'pull' which indicates what kind of algorithm will be used for loading new messages. 'scroll' means that new messages will be loaded when scrollbar of the chat cointainer reaches the top (for desktop) or whole document scrollbar reaches the top (for android). 'click' will show label with 'Click to see earlier messages' and when user clicks it, new messages will be loaded. Finally, 'pull' implements 'pull-to-refresh' behavior used in many modern applications today when new messages loaded by rubber-scrolling the container by more amount than it actually begins. Defaults to 'scroll' for desktop and Android devices and 'pull' for iOS devices.
*/
function Streams_chat_tool($options)
{
    $user = Users::loggedInUser();
    $userId = $user ? $user->id : '';
    /*
    $defaults = array(
    	'loadMore'         => (Q_Request::isTouchscreen() && Q_Request::platform() != 'android') ? 'click' : 'scroll',
    	'messagesToLoad'   => 5,
    	'messageMaxHeight' => 200
    );
    $options = array_merge($defaults, $options);
    */
    extract($options);
    if (!isset($publisherId)) {
        $publisherId = Streams::requestedPublisherId(true);
    }
    if (!isset($streamName)) {
        $streamName = Streams::requestedName();
    }
    $stream = Streams::fetchOne($userId, $publisherId, $streamName);
    if (!$stream) {
        throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => compact('publisherId', 'streamName')));
    }
    $options['userId'] = $userId;
    if (!isset($options['notLoggedIn'])) {
        $options['notLoggedIn'] = 'You are not logged in';
    }
    if (!isset($options['notAuthorized'])) {
        $options['notAuthorized'] = 'You are not authorized';
    }
    Q_Response::setToolOptions($options);
}
Esempio n. 7
0
/**
 * This tool generates an HTML article viewer that lets authorized users edit the article.
 * @class Websites article
 * @constructor
 * @param {Object} [$options] parameters for the tool
 *   @param {String} $options.publisherId The article publisher's user id
 *   @param {String} $options.streamName The article's stream name
 *   @param {String} $options.stream The article's stream, if it is already fetched
 *   @param {String} [$options.html=array()] Any additional for the Streams/html editor
 *   @param {String} [$options.getintouch=array()] Additional options for the Users/getintouch tool, in case it's rendered
 */
function Websites_article_tool($options)
{
    $publisherId = $options['publisherId'];
    $streamName = $options['streamName'];
    $article = Q::ifset($options, 'stream', Streams::fetchOne(null, $publisherId, $streamName));
    if (!$article) {
        throw new Q_Exception_MissingRow(array('table' => 'article', 'criteria' => $streamName));
    }
    $getintouch = array_merge(array('user' => $article->userId, 'email' => true, 'sms' => true, 'call' => true, 'between' => "", 'emailSubject' => 'Reaching out from your website', 'class' => 'Q_button Q_clickable'), Q::ifset($options, 'getintouch', array()));
    $canView = $article->testReadLevel('content');
    $canEdit = $article->testWriteLevel('edit');
    if ($article->getintouch) {
        if (is_array($git = json_decode($article->getintouch, true))) {
            $getintouch = array_merge($getintouch, $git);
        }
    }
    $getintouch['class'] = 'Q_button';
    if (!$canView) {
        throw new Users_Exception_NotAuthorized();
    }
    $html = Q::ifset($options, 'html', array());
    $article->addPreloaded();
    Q_Response::addStylesheet('plugins/Websites/css/Websites.css');
    Q_Response::addScript("plugins/Websites/js/Websites.js");
    Q_Response::setToolOptions($options);
    return Q::view("Websites/tool/article.php", compact('article', 'getintouch', 'canEdit', 'canView', 'html'));
}
Esempio n. 8
0
/**
 * This tool renders all user sessions opened.
 *
 * @param {array} $options An associative array of parameters, containing:
 * @param {string} [$options.userId]
 *   The user's id. Defaults to id of the logged-in user, if any.
 * @param {bool} [$options.editable=true]
 *   Whether user can delete sessions
 * @param {bool} [$options.devices=true]
 *   Whether to show devices info
 */
function Users_sessions_tool($options)
{
    $options = array_merge(array('editable' => true, 'devices' => true), $options);
    if (empty($options['userId'])) {
        $options['userId'] = Users::loggedInUser(true)->id;
    }
    Q_Response::addStylesheet('plugins/Users/css/tools/sessions.css');
    Q_Response::setToolOptions($options);
    $sessions = Users_Session::select("us.*, ud.deviceId, ud.platform, ud.version, ud.formFactor", "us")->join(Users_Device::table() . ' ud', array('us.userId' => 'ud.userId', 'us.id' => 'ud.sessionId'), "LEFT")->where(array('us.userId' => $options['userId']))->fetchDbRows();
    $noDevicesClass = $options['devices'] ? '' : "Users_sessions_noDevices";
    $html = "<table class='Users_sessions_container {$noDevicesClass}'><tr><th>Session Id</th><th class='Users_sessions_devicesData'>Platform</th><th class='Users_sessions_devicesData'>Version</th><th>Last Updated</th>";
    if ($options["editable"]) {
        $html .= '<th class="Users_sessions_actions"></th>';
    }
    $html .= '</tr>';
    foreach ($sessions as $session) {
        $updatedTime = date("M j, Y g:i A", strtotime($session->updatedTime));
        $html .= "<tr><td class='Users_sessions_sessionId'>{$session->id}</td>" . "<td class='Users_sessions_devicesData'>{$session->platform}</td>" . "<td class='Users_sessions_devicesData'>{$session->version}</td>" . "<td>{$updatedTime}</td>";
        if ($options["editable"]) {
            $html .= "<td class='Users_sessions_actions'><button name='delete'>Delete</button></td>";
        }
        $html .= '</tr>';
    }
    $html .= "</table>";
    return $html;
}
Esempio n. 9
0
/**
 * Standard tool for starting or managing subscriptions.
 * @class Assets subscription
 * @constructor
 * @param {array} $options Override various options for this tool
 *  @param {string} $options.payments can be "authnet" or "stripe"
 *  @param {string} $options.planStreamName the name of the subscription plan's stream
 *  @param {string} [$options.publisherId=Q.Users.communityId] the publisher of the subscription plan's stream
 *  @param {string} [$options.subscribeButton] Can override the title of the subscribe button
 *  @param {array} [$options=array()] Any additional options
 *  @param {string} [$options.token=null] required unless the user is an existing customer
 */
function Assets_subscription_tool($options)
{
    if (empty($options['payments'])) {
        throw new Q_Exception_RequiredField(array('field' => 'payments'), 'payments');
    }
    $payments = ucfirst($options['payments']);
    $lcpayments = strtolower($payments);
    $currency = strtolower(Q::ifset($options, 'currency', 'usd'));
    if ($payments === 'Authnet' and $currency !== 'usd') {
        throw new Q_Exception("Authnet doesn't support currencies other than USD", 'currency');
    }
    $className = "Assets_Payments_{$payments}";
    switch ($payments) {
        case 'Authnet':
            $adapter = new $className($options);
            $token = $options['token'] = $adapter->authToken();
            $testing = $options['testing'] = Q_Config::expect('Assets', 'payments', $lcpayments, 'testing');
            $action = $options['action'] = $testing ? "https://test.authorize.net/profile/manage" : "https://secure.authorize.net/profile/manage";
            break;
        case 'Stripe':
            $publishableKey = Q_Config::expect('Assets', 'payments', 'stripe', 'publishableKey');
            break;
    }
    $titles = array('Authnet' => 'Authorize.net', 'Stripe' => 'Stripe');
    $subscribeButton = Q::ifset($options, 'subscribeButton', "Subscribe with " . $titles[$payments]);
    Q_Response::setToolOptions($options);
    return Q::view("Assets/tool/subscription/{$payments}.php", compact('token', 'publishableKey', 'action', 'paymentButton', 'subscribeButton', 'planStreamName'));
}
Esempio n. 10
0
/**
 * This tool renders a user avatar
 *
 * @param {array} $options An associative array of parameters, containing:
 * @param {boolean} [$options.userId]
 *   "userId" => The user's id. Defaults to id of the logged-in user, if any.
 * @param {boolean} [$options.icon]
 *   "icon" => Optional. Render icon before the username.
 * @param {boolean} [$options.iconAttributes]
 *   "iconAttributes" => Optional. Array of attributes to render for the icon.
 * @param {boolean} [$options.editable]
 *   "editable" => Optional. Whether to provide an interface for editing the user's info. Can be array containing "icon", "name".
 * @param {array} [$options.inplaces] Additional fields to pass to the child Streams/inplace tools, if any
 * @param {boolean} [$options.renderOnClient]
 *    If true, only the html container is rendered, so the client will do the rest.
 */
function Users_avatar_tool($options)
{
    $defaults = array('icon' => false, 'editable' => false);
    $options = array_merge($defaults, $options);
    if (empty($options['userId'])) {
        $user = Users::loggedInUser();
        $options['userId'] = $user->id;
    } else {
        $user = Users_User::fetch($options['userId']);
    }
    Q_Response::addStylesheet('plugins/Q/css/Q.css');
    Q_Response::setToolOptions($options);
    if (!empty($options['renderOnClient'])) {
        return '';
    }
    if (!$user) {
        return '';
    }
    $user->addPreloaded();
    $p = $options;
    $p['userId'] = $user->id;
    Q_Response::setToolOptions($p);
    $result = '';
    $icon = $options['icon'];
    if ($icon) {
        if ($icon === true) {
            $icon = Q_Config::get('Users', 'icon', 'defaultSize', 40);
        }
        $attributes = isset($options['iconAttributes']) ? $options['iconAttributes'] : array();
        $attributes['class'] = isset($attributes['class']) ? $attributes['class'] . ' Users_avatar_icon' : 'Users_avatar_icon';
        $result .= Q_Html::img($user->iconUrl($icon), 'user icon', $attributes);
    }
    $result .= '<span class="Users_avatar_name">' . $user->username . '</span>';
    return $result;
}
Esempio n. 11
0
/**
 * Renders a photo selector tool
 * @param $options
 *   An associative array of parameters, which can include:
 * @param {Object} [$options] this object contains function parameters
 *   @param {Q.Event} $options.onSelect Required string naming the callback to be called when the user selects a photo.
 *   @param {Q.Event} [$options.beforePhotos] Triggered when photos are about to be rendered.
 *   @param {Q.Event} [$options.onPhotos] Triggered when photos have been rendered.
 *   @param {String} [$options.uid='me'] Optional. The uid of the user on the provider whose photos should be shown. Facebook only allows 'me' or a page id as a value.
 *   @param {String} [$options.fetchBy='album'] The tool supports different algoriths for fetching photos. Can be either by 'album' or 'tags'. Maybe more will be added later.
 *   @param {String} [$options.preprocessAlbums] Optional function to process the albums array before presenting it in the select. Receives a reference to the albums array as the first parameter, and a callback to call when it's done as the second.
 *   @param {String} [$options.preprocessPhotos] Optional function to process the photos array before presenting it in the select. Receives a reference to the albums array as the first parameter, and a callback to call when it's done as the second.
 *   @param {Q.Event} [$options.onLoad] Q.Event, callback or callback string name which is called when bunch of photos has been loaded.
 *   @param {Q.Event} [$options.onError] Q.Event, callback or callback string which will be called for each image that is unable to load. Image DOM element will be passed as first argument.
 *   @param {String} [$options.provider='facebook'] Has to be "facebook" for now.
 *   @param {String} [$options.prompt=false]
 *   Specifies type of prompt if user is not logged in or didn't give required permission for the tool.
 *   Can be either 'button', 'dialog' or null|false. 
 *   In first case just shows simple button which opens facebook login popup.
 *   In second case shows Users.facebookDialog prompting user to login.
 *   In third case will not show any prompt and will just hide the tool.
 *   @param {String} [$options.promptTitle]  Used only when 'prompt' equals 'dialog' - will be title of the dialog.
 *   @param {String} [$options.promptText]  Used either for button caption when 'prompt' equals 'button' or dialog text when 'prompt' equals 'dialog'.
 *   @param {Boolean} [$options.oneLine]  If true, all the images are shown in a large horizontally scrolling line.
 * @return {void}
 */
function Streams_photoSelector_tool($options)
{
    Q_Response::addScript('plugins/Streams/js/Streams.js');
    Q_Response::addStylesheet('plugins/Streams/css/Streams.css');
    Q_Response::setToolOptions($options);
    return '';
}
Esempio n. 12
0
/**
 * This tool renders a user avatar
 *
 * @param {array} $options An associative array of parameters, containing:
 * @param {string} [$options.userId]
 *   The user's id. Defaults to id of the logged-in user, if any.
 *   Can be '' for a blank-looking avatar.
 * @param {boolean} [options.short]
 *   Optional. Renders the short version of the display name.
 * @param {boolean|integer} [options.icon=false]
 *   Optional. Pass the size in pixels of the (square) icon to render
 *   before the username. Or pass true to render the default size.
 * @param {array} [options.iconAttributes]
 *   Optional. Array of attributes to render for the icon.
 * @param {boolean|array} [options.editable=false]
 *   Optional. Whether to provide an interface for editing the user's info. Can be array containing one or more of "icon", "name".
 * @param {boolean} [$options.show] The parts of the name to show. Can have the letters "f", "l", "u" in any order.
 * @param {boolean} [options.cacheBust=null]
 *   Number of milliseconds to use for Q_Uri::cacheBust for combating unintended caching on some environments.
 * @param {boolean} [options.renderOnClient]
 *   If true, only the html container is rendered, so the client will do the rest.
 */
function Users_avatar_tool($options)
{
    $defaults = array('icon' => false, 'short' => false, 'cacheBust' => null, 'editable' => false);
    $options = array_merge($defaults, $options);
    Q_Response::addStylesheet('plugins/Users/css/Users.css');
    $loggedInUser = Users::loggedInUser();
    $loggedInUserId = $loggedInUser ? $loggedInUser->id : "";
    if (empty($options['userId'])) {
        $options['userId'] = $loggedInUserId;
    }
    unset($options['iconAttributes']);
    if (empty($options['editable'])) {
        $options['editable'] = array();
    } else {
        if (is_string($options['editable'])) {
            $options['editable'] = array($options['editable']);
        } else {
            if ($options['editable'] === true) {
                $options['editable'] = array('icon', 'name');
            }
        }
    }
    Q_Response::setToolOptions($options);
    if (!empty($options['renderOnClient'])) {
        return '';
    }
    $avatar = Streams_Avatar::fetch($loggedInUserId, $options['userId']);
    if (!$avatar) {
        return '';
    }
    $result = '';
    if ($icon = $options['icon']) {
        if ($icon === true) {
            $icon = Q_Config::get('Users', 'icon', 'defaultSize', 40);
        }
        $attributes = isset($options['iconAttributes']) ? $options['iconAttributes'] : array();
        $class = "Users_avatar_icon Users_avatar_icon_{$icon}";
        $attributes['class'] = isset($attributes['class']) ? $attributes['class'] . ' ' . $class : $class;
        if (isset($options['cacheBust'])) {
            $attributes['cacheBust'] = $options['cacheBust'];
        }
        $result .= Q_Html::img(Users::iconUrl($avatar->icon, "{$icon}.png"), 'user icon', $attributes);
    }
    $o = $options['short'] ? array('short' => true) : array();
    $o['html'] = true;
    if (in_array('name', $options['editable'])) {
        $o['show'] = 'fl';
        $streams = Streams::fetch(null, $options['userId'], array('Streams/user/firstName', 'Streams/user/lastName', 'Streams/user/username'));
        foreach ($streams as $s) {
            $s->addPreloaded();
        }
    }
    if (!empty($options['show'])) {
        $o['show'] = $options['show'];
    }
    $displayName = $avatar->displayName($o, 'Someone');
    $result .= "<span class='Users_avatar_name'>{$displayName}</span>";
    return $result;
}
Esempio n. 13
0
/**
 * Makes an infomation block for adding a bookmarklet on the browser's bookmarks bar
 * the way similar to how facebook does: https://www.facebook.com/share_options.php .
 * Main purpose of the tool is to present in cross-browser way how bookmarklet button will look, how bookmarklet will
 * look on browser panel and instructions how to add bookmarklet to that panel.
 * @param {array} $options An associative array of parameters, which can include:
 * @param {array} [$options.scripts] Array of one or more urls of javascript files (will be run through Q_Html::themedUrl) to be executed in order.
 * @param {string} [$options.content] Literal Javascript code to execute. If scripts option is provided, this code is executed after the scripts have been loaded.
 * @param {Object} [$options.skip] Object of {url: path.to.object} pairs to avoid loading script at the url if path.to.object is already defined. Typically names an object which has been defined by the loaded script.
 * @param {string} $options.title Required. Title for the button which will be added to user's browser bar.
 * @param {string} $options.usage Text which is appended to instructions, identifying purpose and usage of this bookmarklet.
 * @param {string} [$options.icon] Icon for the button which will be added to user's browser bar. Can contain placeholders supported by strftime() and also few special placeholders with specific functionality.
 * @return {string}
 */
function Q_bookmarklet_tool($options)
{
    $options = array_merge(array('icon' => null), $options);
    Q_Response::addScript('plugins/Q/js/tools/bookmarklet.js');
    Q_Response::addStylesheet('plugins/Q/css/bookmarklet.css');
    Q_Response::setToolOptions($options);
    return '';
}
Esempio n. 14
0
/**
 * Renders a bunch of Stream/preview tools for streams related to the given stream.
 * Has options for adding new related streams, as well as sorting the relations, etc.
 * Also can integrate with Q/tabs tool to render tabs "related" to some category.
 * @class Streams related
 * @constructor
 * @param {array} $options options for the tool
 *   @param {string} [$options.publisherId] Either this or "stream" is required. Publisher id of the stream to which the others are related
 *   @param {string} [$options.streamName] Either this or "stream" is required. Name of the stream to which the others are related
 *   @param {string} [$options.tag="div"] The type of element to contain the preview tool for each related stream.
 *   @param {string} [$options.stream] You can pass a Streams_Stream object here instead of "publisherId" and "streamName"
 *   @param {string} [$options.relationType=""] The type of the relation.
 *   @param {boolean} [$options.isCategory=true] Whether to show the streams related TO this stream, or the ones it is related to.
 *   @param {array} [$options.relatedOptions] Can include options like 'limit', 'offset', 'ascending', 'min', 'max', 'prefix' and 'fields'
 *   @param {boolean} [$options.editable] Set to false to avoid showing even authorized users an interface to replace the image or text
 *   @param {array} [$options.creatable]  Optional pairs of {streamType: toolOptions}  to render Streams/preview tools create new related streams.
 *   The params typically include at least a "title" field which you can fill with values such as "New" or "New ..."
 *   @param {Function} [options.toolName] Optionally name a function that takes (streamType, options) and returns the name of the tool to render (and then activate) for that stream. That tool should reqire the "Streams/preview" tool, and work with it as documented in "Streams/preview".
 *   @param {boolean} [$options.realtime=false] Whether to refresh every time a relation is added, removed or updated by anyone
 *   @param {array} [$options.sortable] Options for "Q/sortable" jQuery plugin. Pass false here to disable sorting interface. If streamName is not a String, this interface is not shown.
 *   @param {string} [$options.tabs] Name of a cuntion for interacting with any parent "Q/tabs" tool. Format is function (previewTool, tabsTool) { return urlOrTabKey; }
 *   @param {array} [$options.updateOptions] Options for onUpdate such as duration of the animation, etc.
 *   @param {string} [$options.onUpdate] Name of a handler for event that receives parameters "data", "entering", "exiting", "updating"
 *   @param {string} [$options.onRefresh] Name of a handler for event that occurs when the tool is completely refreshed, the "this" is the tool
 */
function Streams_related_tool($options)
{
    if (!empty($options['stream'])) {
        $stream = $options['stream'];
        $options['publisherId'] = $stream->publisherId;
        $options['streamName'] = $stream->name;
    }
    Q_Response::setToolOptions($options);
}
Esempio n. 15
0
/**
 * This tool generates an inline editor to edit the content or attribute of a stream.
 * @class Streams inplace
 * @constructor
 * @param {array} $options Options for the tool
 *  An associative array of parameters, containing:
 * @param {string} [$options.inplaceType='textarea'] The type of the fieldInput. Can be "textarea" or "text"
 * @param {array} [$options.convert] The characters to convert to HTML. Pass an array containing zero or more of "\n", " "
 * @param {Streams_Stream} $options.stream A Streams_Stream object
 * @param {string} [$options.field] Optional, name of an field to change instead of the content of the stream
 * @param {string} [$options.attribute] Optional, name of an attribute to change instead of any field.
 * @param {string} [$options.beforeSave] Reference to a callback to call after a successful save. This callback can cancel the save by returning false.
 * @param {string} [$options.onSave] Reference to a callback or event to run after a successful save.
 * @param {string} [$options.onCancel] Reference to a callback or event to run after cancel.
 * @param {array} [$options.inplace=array()] Additional fields to pass to the child Q/inplace tool, if any
 * @uses Q inplace
 */
function Streams_inplace_tool($options)
{
    if (empty($options['stream'])) {
        if (empty($options['publisherId']) or empty($options['streamName'])) {
            throw new Q_Exception_RequiredField(array('field' => 'stream'));
        }
        $publisherId = $options['publisherId'];
        $streamName = $options['streamName'];
        $stream = Streams::fetchOne(null, $publisherId, $streamName);
        if (!$stream) {
            throw new Q_Exception_MissingRow(array('table' => 'stream', 'criteria' => "publisherId={$publisherId}, name={$streamName}"));
        }
    } else {
        $stream = $options['stream'];
    }
    $inplaceType = Q::ifset($options, 'inplaceType', 'textarea');
    $inplace = array('action' => $stream->actionUrl(), 'method' => 'PUT', 'type' => $inplaceType);
    if (isset($options['inplace'])) {
        $inplace = array_merge($options['inplace'], $inplace);
    }
    $convert = Q::ifset($options, 'convert', array("\n"));
    $inplace['hidden']['convert'] = json_encode($convert);
    if (!empty($options['attribute'])) {
        $field = 'attributes[' . urlencode($options['attribute']) . ']';
        $content = $stream->get($options['attribute'], '');
        $maxlength = $stream->maxSize_attributes - strlen($stream->maxSize_attributes) - 10;
    } else {
        $field = !empty($options['field']) ? $options['field'] : 'content';
        $content = $stream->{$field};
        $maxlength = $stream->maxSizeExtended($field);
    }
    switch ($inplaceType) {
        case 'text':
            $inplace['fieldInput'] = Q_Html::input($field, $content, array('placeholder' => Q::ifset($input, 'placeholder', null), 'maxlength' => $maxlength));
            $inplace['staticHtml'] = Q_Html::text($content);
            break;
        case 'textarea':
            $inplace['fieldInput'] = Q_Html::textarea($field, 5, 80, array('placeholder' => Q::ifset($inplace, 'placeholder', null), 'maxlength' => $maxlength), $content);
            $inplace['staticHtml'] = Q_Html::text($content, $convert);
            break;
        default:
            return "inplaceType must be 'textarea' or 'text'";
    }
    if (!$stream->testWriteLevel('suggest')) {
        if (!isset($options['classes'])) {
            $options['classes'] = '';
        }
        Q_Response::setToolOptions(array('publisherId' => $stream->publisherId, 'streamName' => $stream->name));
        $staticClass = $options['inplaceType'] === 'textarea' ? 'Q_inplace_tool_blockstatic' : 'Q_inplace_tool_static';
        return "<span class='Q_inplace_tool_container {$options['classes']}' style='position: relative;'>" . "<div class='{$staticClass}'>{$inplace['staticHtml']}</div></span>";
    }
    $toolOptions = array('publisherId' => $stream->publisherId, 'streamName' => $stream->name, 'inplaceType' => $options['inplaceType']);
    Q::take($options, array('attribute', 'field', 'convert'), $toolOptions);
    $toolOptions['inplace'] = $inplace;
    Q_Response::setToolOptions($toolOptions);
    return Q::tool("Q/inplace", $inplace);
}
Esempio n. 16
0
/**
* Renders a comment form and comments feed which is looking like standard Facebook.
* @param $options
*   An associative array of parameters, which can include:
*   "objectId" => Required. A Graph object id which is used to load comments from it and post comments to it.
*   "provider" => Optional. Has to be "facebook" for now.
* @return {string}
*/
function Streams_comments_tool($options)
{
    Q_Response::addScript('plugins/Q/js/phpjs.js');
    Q_Response::addScript('plugins/Streams/js/Streams.js');
    Q_Response::addStylesheet('plugins/Streams/css/Streams.css');
    Q_Response::addStylesheet('plugins/Users/css/Users.css');
    Q_Response::setToolOptions($options);
    return Q::view('Streams/tool/comments.php');
}
Esempio n. 17
0
/**
 * Renders a search tool which is able to search in streams using query typed by user.
 * @param $options
 *   An associative array of parameters, which can include:
 *   "placeholder" => Optional. Search field placeholder text. Default is "search".
 *   "submit" => Optional. Submit button text (or arbitrary html content). Default is "Submit". If 'false' value is passed, then submit button is not added.
 * @return {string}
 */
function Streams_search_tool($options)
{
    Q_Response::addScript('plugins/Streams/js/Streams.js');
    Q_Response::addStylesheet('plugins/Streams/css/Streams.css');
    $default = array('placeholder' => 'search', 'submit' => 'Submit');
    $options = array_merge($default, $options);
    Q_Response::setToolOptions($options);
    return Q::view('Streams/tool/search.php', $options);
}
Esempio n. 18
0
/**
 * Renders a user status area which displays logged in status and provides various user-related operations.
 * @param $options
 *   An associative array of parameters, which can include:
 *   "icon" => Optional. Icon for the login button. Defaults to Qbix icon.
 *   "label" => Optional. Text for the login button. Defaults to 'log in'.
 *   "logoutIcon" => Optional. Icon for 'Log out' item in the tool menu.
 *   "menuItems" => Optional. Additional menu items beside 'Log out' which will be shown in user menu.
 *                  Should be an array of hashes like { 'contents': 'value', 'action': 'value' }.
 *   "onCancel" => Optional. Function, string function name or Q.Event. Called when user was unable to login or cancelled login dialog.
 *   "onLogin" => Optional. Function or Q.Event. Called when user successfully logged it.
 *   "onLogout" => Optional. Function, string function name or Q.Event. Called when user successfully logged out.
 *   "onMenuSelect" => Optional. Function, string function name or Q.Event.
 *                     Called when user selected some item from user selected some item from user menu except 'Log out'.
 * @return {string}
 */
function Users_status_tool($options)
{
    $defaults = array('icon' => 'plugins/Q/img/ui/qbix_icon' . (Q_Request::isMobile() ? '_small' : '') . '.png', 'label' => 'log in', 'logoutIcon' => null, 'menuItems' => array(), 'onCancel' => null, 'onLogin' => null, 'onLogout' => null, 'onMenuSelect' => null);
    $options = array_merge($defaults, $options);
    Q_Response::addStylesheet('plugins/Q/css/Q.css');
    Q_Response::addStylesheet('plugins/Users/css/Users.css');
    Q_Response::setToolOptions($options);
    return Q::view('Users/tool/status/status.php', $options);
}
Esempio n. 19
0
/**
 * This tool contains functionality to show things in columns
 * @class Q columns
 * @constructor
 * @param {array}   [options] Provide options for this tool
 *  @param {array}  [options.animation] For customizing animated transitions
 *  @param {integer}  [options.animation.duration] The duration of the transition in milliseconds, defaults to 500
 *  @param {array}  [options.animation.hide] The css properties in "hide" state of animation
 *  @param {array}  [options.animation.show] The css properties in "show" state of animation
 *  @param {array}  [options.back] For customizing the back button on mobile
 *  @param {string}  [options.back.src] The src of the image to use for the back button
 *  @param {boolean} [options.back.triggerFromTitle] Whether the whole title would be a trigger for the back button. Defaults to true.
 *  @param {boolean} [options.back.hide] Whether to hide the back button. Defaults to false, but you can pass true on android, for example.
 *  @param {array}  [options.close] For customizing the back button on desktop and tablet
 *  @param {string}  [options.close.src] The src of the image to use for the close button
 *  @param {string}  [options.title] You can put a default title for all columns here (which is shown as they are loading)
 *  @param {string}  [options.column] You can put a default content for all columns here (which is shown as they are loading)
 *  @param {array}  [options.clickable] If not null, enables the Q/clickable tool with options from here. Defaults to null.
 *  @param {array}  [options.scrollbarsAutoHide] If not null, enables Q/scrollbarsAutoHide functionality with options from here. Enabled by default.
 *  @param {boolean} [options.fullscreen] Whether to use fullscreen mode on mobile phones, using document to scroll instead of relying on possibly buggy "overflow" CSS implementation. Defaults to true on Android, false everywhere else.
 *  @param {array}   [options.columns] In PHP only, an array of $name => $column pairs, where $column is in the form array('title' => $html, 'content' => $html, 'close' => true)
 * @return {string}
 */
function Q_columns_tool($options)
{
    $jsOptions = array('animation', 'back', 'close', 'title', 'scrollbarsAutoHide', 'fullscreen');
    Q_Response::setToolOptions(Q::take($options, $jsOptions));
    if (!isset($options['columns'])) {
        return '';
    }
    Q_Response::addScript('plugins/Q/js/tools/columns.js');
    Q_Response::addStylesheet('plugins/Q/css/columns.css');
    $result = '<div class="Q_columns_container Q_clearfix">';
    $columns = array();
    $i = 0;
    $closeSrc = Q::ifset($options, 'close', 'src', 'plugins/Q/img/x.png');
    $backSrc = Q::ifset($options, 'back', 'src', 'plugins/Q/img/back-v.png');
    foreach ($options['columns'] as $name => $column) {
        $close = Q::ifset($column, 'close', $i > 0);
        $Q_close = Q_Request::isMobile() ? 'Q_close' : 'Q_close Q_back';
        $closeHtml = !$close ? '' : (Q_Request::isMobile() ? '<div class="Q_close Q_back">' . Q_Html::img($backSrc, 'Back') . '</div>' : '<div class="Q_close">' . Q_Html::img($closeSrc, 'Close') . '</div>');
        $n = Q_Html::text($name);
        $columnClass = 'Q_column_' . Q_Utils::normalize($name) . ' Q_column_' . $i;
        if (isset($column['html'])) {
            $html = $column['html'];
            $columns[] = <<<EOT
\t<div class="Q_columns_column {$columnClass}" data-index="{$i}" data-name="{$n}">
\t\t{$html}
\t</div>
EOT;
        } else {
            $titleHtml = Q::ifset($column, 'title', '[title]');
            $columnHtml = Q::ifset($column, 'column', '[column]');
            $classes = $columnClass . ' ' . Q::ifset($column, 'class', '');
            $attrs = '';
            if (isset($column['data'])) {
                $json = Q::json_encode($column['data']);
                $attrs = 'data-more="' . Q_Html::text($json) . '"';
                foreach ($column['data'] as $k => $v) {
                    $attrs .= 'data-' . Q_Html::text($k) . '="' . Q_Html::text($v) . '" ';
                }
            }
            $data = Q::ifset($column, 'data', '');
            $columns[] = <<<EOT
\t<div class="Q_columns_column {$classes}" data-index="{$i}" data-name="{$n}" {$attrs}>
\t\t<div class="Q_columns_title">
\t\t\t{$closeHtml}
\t\t\t<h2 class="Q_title_slot">{$titleHtml}</h2>
\t\t</div>
\t\t<div class="Q_column_slot">{$columnHtml}</div>
\t</div>
EOT;
        }
        ++$i;
    }
    $result .= "\n" . implode("\n", $columns) . "\n</div>";
    return $result;
}
Esempio n. 20
0
/**
 * Implements an input that filters an associated list (like an autocomplete)
 * @class Q filter
 * @constructor
 * @param {array} [$options] Override various options for this tool
 *  @param {String} [$options.name=filter] The name of the text input
 *  @param {String} [$options.value=''] The initial value of the text input
 *  @param {String} [$options.placeholder] Any placeholder text
 *  @param {array} [$options.placeholders={}] Options for Q/placeholders, or null to omit it
 *  @param {String} [$options.results=''] HTML to display in the results initially. If setting them later, remember to call stateChanged('results')
 *  @param {Q.Event} [$options.onFilter] Name of a JS event handler that is meant to fetch and update results by editing the contents of the element pointed to by the second argument. The first argument is the content of the text input.
 * @return {string}
 */
function Q_filter_tool($options)
{
    Q_Response::setToolOptions($options);
    $name = Q::ifset($options, 'name', 'filter');
    $value = Q::ifset($options, 'value', '');
    $placeholder = Q::ifset($options, 'placeholder', 'filter');
    $class = 'Q_filter_input';
    Q_Response::addScript('plugins/Q/js/tools/filter.js');
    Q_Response::addStylesheet('plugins/Q/css/filter.css');
    return Q_Html::input($name, $value, compact('placeholder', 'class')) . '<div class="Q_filter_results"></div>';
}
Esempio n. 21
0
/**
 * userChooser tool
 * @param array $options
 *  "maxResults" => the maximum number of results to show, defaults to 3
 *  "onSuccess" => the name of the function for what to do
 *  "placeholder" => override the default placeholder text,
 *  "exclude" => associative array of userId => true, where userId are the ids of the users
 *    to exclude from the results. Defaults to id of logged-in user, if logged in.
 */
function Streams_userChooser_tool($options)
{
    $maxResults = Q_Config::get('Streams', 'userChooser', 'maxResults', 3);
    $placeholder = "Start typing...";
    extract($options);
    if (!isset($exclude) and $user = Users::loggedInUser()) {
        $exclude = array($user->id => true);
    }
    Q_Response::addScript('plugins/Streams/js/Streams.js');
    Q_Response::setToolOptions(compact('onSuccess', 'maxResults', 'exclude'));
    return Q_Html::input('query', '', array('class' => 'text', 'placeholder' => $placeholder, 'autocomplete' => 'off'));
}
Esempio n. 22
0
/**
 * Creates an area that behaves like position: fixed in most modern browsers,
 * including ones on touchscreens. Often used for fixed areas that wind up
 * covered by content as it scrolls over the areas.
 * @class Q drawers
 * @constructor
 * @param {array}   [$options] Provide options for this tool
 *  @param {array}   [$options.drawers] Array of strings holding html for drawers
 *  @param {string} [$options.container=null] Optional jQuery selector for handling scrolling
 *  @param {array}   [$options.initial] Information for the initial animation
 *  @param {integer}   [$options.initial.index=1] The index of the drawer to show, either 0 or 1
 *  @param {integer}   [$options.initial.delay=0] Delay before starting initial animation
 *  @param {integer}   [$options.initial.duration=300] The duration of the initial animation
 *  @param {Function} [$options.initial.ease=Q.Animation.linear] The easing function of the initial animation
 *  @param {array}   [$options.transition] Information for the transition animation
 *  @param {integer}   [$options.transition.duration=300] The duration of the transition animation
 *  @param {Function}   [$options.transition.ease=Q.Animation.linear] The easing function of the transition animation
 *  @param {Function}   [$options.width] Override the function that computes the width of the drawers
 *  @param {Function}   [$options.height] Override the function that computes the height drawers tool
 *  @param {array}   [$options.heights=[100,100]] Array of [height0, height1] for drawers that are pinned
 *  @param {array}   [$options.placeholders=['','']] Array of [html0, html1] for drawers that are pinned
 *  @param {array}   [$options.behind=[true,false]] Array of [boolean0, boolean1] to indicate which drawer is behind the others
 *  @param {array}   [$options.bottom=[false,false]] Array of [boolean0, boolean1] to indicate whether to scroll to the bottom of a drawer after switching to it
 *  @param {array}   [$options.triggers=['plugins/Q/img/drawers/up.png', 'plugins/Q/img/drawers/down.png']] Array of [src0, src1] for img elements that act as triggers to swap drawers. Set array elements to false to avoid rendering a trigger.
 *  @param {array}   [$options.trigger]] Options for the trigger elements
 *  @param {integer}   [$options.trigger.rightMargin=10]] How many pixels from the right side of the drawers
 *  @param {integer}   [$options.transition=300]] Number of milliseconds for fading in the trigger images
 *  @param {boolean}   [$options.fullscreen=Q.info.isAndroidStock && Q.info.isAndroid(1000)]] Whether the drawers should take up the whole screen
 *  @param {integer}   [$options.foregroundZIndex=50] The z-index of the drawer in the foreground
 *  @param {integer}   [$options.beforeSwap=new Q.Event()] Occurs right before drawer swap
 *  @param {integer}   [$options.onSwap=new Q.Event()] Occurs right after drawer swap
 */
function Q_drawers_tool($options)
{
    $result = '';
    foreach ($options['drawers'] as $i => $html) {
        $result .= Q_Html::div("drawer_{$i}", "Q_drawers_drawer Q_drawers_drawer_{$i}", $html);
    }
    unset($options['drawers']);
    Q_Response::addScript('plugins/Q/js/tools/drawers.js');
    Q_Response::addStylesheet('plugins/Q/css/drawers.css');
    Q_Response::setToolOptions($options);
    return $result;
}
Esempio n. 23
0
/**
 * Lets the user search for streams they can relate a given stream to, and relate it
 * @class Streams relate
 * @constructor
 * @param {array} [$options] Override various options for this tool
 * @param {string} $publisherId publisher id of the stream to relate
 * @param {string} $streamName name of stream to relate
 * @param {string} [$communityId=Users::communityId()] id of the user publishing the streams to relate to
 * @param {array} [$types=Q_Config::expect('Streams','relate','types')] the types of streams the user can select
 * @param {array} [$typeNames] pairs of array($type => $typeName) to override names of the types, which would otherwise be taken from the types
 * @param {Boolean} [options.multiple=true] whether the user can select multiple types for the lookup
 * @param {boolean} [$relateFrom=false] if true, will relate FROM the user-selected stream TO the streamName instead
 * @param {string} [$types=Q_Config::expect('Streams','relate','types')] the types of streams the user can select
 * @param {Q.Event} [$options.onRelate] This event handler occurs when a stream is successfully related
 */
function Streams_relate_tool($options)
{
    Q_Valid::requireFields(array('publisherId', 'streamName'), $options, true);
    if (!isset($options['communityId'])) {
        $options['communityId'] = Users::communityId();
    }
    if (!isset($options['types'])) {
        $options['types'] = Q_Config::get('Streams', 'relate', 'types', array());
    }
    Q_Response::setToolOptions($options);
    return '';
}
Esempio n. 24
0
/**
 * This tool generates a category selector.
 *
 * @param {array} $options An associative array of parameters, containing:
 * @param {string} [$options.publisherId=Streams::requestedPublisherId()] The publisherId of the stream to present. If "stream" parameter is empty
 * @param {string} [$options.streamName=Streams::requestedName()] The streamName of the stream to present. If "stream" parameter is empty
 * @param {string} [options.relationType=null] Filter the relation type.
 */
function Streams_category_tool($options)
{
    extract($options);
    if (!$publisherId) {
        $options['publisherId'] = $publisherId = Streams::requestedPublisherId(true);
    }
    if (!$streamName) {
        $options['streamName'] = $streamName = Streams::requestedName(true);
    }
    Q_Response::setToolOptions($options);
    $stream = Streams::fetchOne(null, $publisherId, $streamName, true);
    $userId = Users::loggedInUser(true)->id;
    return Q::tool('Streams/related', $options);
}
Esempio n. 25
0
/**
 * Inplace text editor tool to edit the content or attribute of a stream
 * @class Places location
 * @constructor
 * @param {Object} [options] used to pass options
 * @param {Object} [options.miles] array of { miles: title } pairs, defaults to Places/nearby/miles config
 * @param {Object} [options.map] options for the map
 * @param {Number} [options.map.delay=300] how many milliseconds to delay showing the map, e.g. because the container is animating
 * @param {String} [options.map.prompt="img/map.png"] The src of the map graphical prompt when no location has been selected yet
 * @param {Q.Event} [options.onUpdate] this event occurs when the location is updated
 * @param {Q.Event} [options.onUnset] this event occurs when the location is unset
 */
function Places_location_tool($options)
{
    if (empty($options['miles'])) {
        $options['miles'] = array();
        foreach (Q_Config::expect('Places', 'nearby', 'miles') as $m) {
            $options['miles'][$m] = $m === 1 ? "{$m} mile" : "{$m} miles";
        }
    }
    if (empty($options['map']['prompt'])) {
        $options['map']['prompt'] = 'plugins/Places/img/map.png';
    }
    Q_Response::setToolOptions($options);
    return Q::view("Places/tool/location.php", $options);
}
Esempio n. 26
0
/**
 * Inline editor for HTML content
 * @class Streams html
 * @constructor
 * @param {array} [$options] this array contains function parameters
 *   @param {string} $options.publisherId  The publisher's user id.
 *   @param {string} $options.field The name of the stream field used to save the html.
 *   @param {string} [$options.streamName] If empty, and "creatable" is true, then this can be used to add new related streams.
 *   @param {string} [$options.placeholder] The placeholder HTML
 *   @param {string} [$options.editor="auto"]  Can be "ckeditor", "froala", "basic" or "auto".
 *   @param {boolean} [$options.editable] Set to false to avoid showing even authorized users an interface to replace the contents
 *   @param {array} [$options.ckeditor]  The config, if any, to pass to ckeditor
 *   @param {array} [$options.froala]  The config, if any, to pass to froala
 *   @param {string} [$options.preprocess]  Name of an optional function which takes [callback, tool] and calls callback(objectToExtendAnyStreamFields)
 */
function Streams_html_tool($options)
{
    $stylesheets = array("plugins/Q/font-awesome/css/font-awesome.min.css", "plugins/Q/js/froala/css/froala_editor.min.css", "plugins/Q/js/froala/css/froala_style.min.css", "plugins/Q/js/froala/css/plugins/fullscreen.min.css", "plugins/Q/js/froala/css/plugins/colors.min.css", "plugins/Q/js/froala/css/plugins/image.min.css", "plugins/Q/js/froala/css/plugins/table.min.css", "plugins/Q/js/froala/css/plugins/code_view.min.css");
    foreach ($stylesheets as $stylesheet) {
        Q_Response::addStylesheet($stylesheet);
    }
    if ($froalaKey = Q_Config::get('Streams', 'froala', 'key', null)) {
        if (!empty($options['froala'])) {
            $options['froala'] = array();
        }
        $options['froala']['key'] = $froalaKey;
    }
    Q_Response::setToolOptions($options);
}
Esempio n. 27
0
/**
 * Inplace text editor tool to edit the content or attribute of a stream
 * @class Places location
 * @constructor
 * @param {array} [$options] used to pass options
 * @param {array} [$options.miles] array of { miles: title } pairs, by default is generated from Places/nearby/miles config
 * @param {array} [$options.defaultMiles] override the key in the miles array to select by default. Defaults to "Places/nearby/defaultMiles" config
 * @param {array} [$options.map] options for the map
 * @param {integer} [$options.map.delay=300] how many milliseconds to delay showing the map, e.g. because the container is animating
 * @param {string} [$options.map.prompt="img/map.png"] The src of the map graphical prompt when no location has been selected yet
 * @param {String} [$options.updateButton="Update my location"] the title of the update button
 * @param {string} [$options.onUpdate] name an event handler for when the location is updated
 * @param {string} [$options.onUnset] name an event handler for when the location is unset
 */
function Places_location_tool($options)
{
    if (empty($options['miles'])) {
        $options['miles'] = array();
        foreach (Q_Config::expect('Places', 'nearby', 'miles') as $m) {
            $options['miles'][$m] = $m === 1 ? "{$m} mile" : "{$m} miles";
        }
    }
    if (empty($options['map']['prompt'])) {
        $options['map']['prompt'] = Q_Html::themedUrl('plugins/Places/img/map.png');
    }
    if (!isset($options['defaultMiles'])) {
        $options['defaultMiles'] = Q_Config::expect('Places', 'nearby', 'defaultMiles');
    }
    Q_Response::setToolOptions($options);
    return '';
}
Esempio n. 28
0
/**
 * This tool renders ways to get in touch
 *
 * @param array [$options] An associative array of options, containing:
 *   @param {string|Users_User} [$options.user] Required. The user object or id of the user exposing their primary identifiers for getting in touch.
 *   @param {boolean|string} [$options.email] Pass true here to use the primary verified email address, if any. Or pass the string label for this button.
 *   @param {string} [$options.emailSubject] Fill this if you want the email subject to be automatically filled in
 *   @param {string} [$options.emailBody] Fill this if you want the email body to be automatically filled in
 *   @param {boolean|string} [$options.sms] Pass true here to allow texting the primary verified mobile number, if any. Or pass the string label for this button.
 *   @param {boolean|string} [$options.call] Pass true here to allow calling the primary verified mobile number, if any. Or pass the string label for this button.
 *   @param {string} [$options.tag] The type of tag to use, defaults to "button"
 *   @param {string} [$options.class] Any classes to add to the tags
 *   @param {string} [$options.between] Any HTML to put between the elements
 */
function Users_getintouch_tool($options)
{
    $tag = 'button';
    $class = null;
    $between = '';
    $user = null;
    $emailSubject = '';
    $emailBody = '';
    extract($options, EXTR_IF_EXISTS);
    if (!$user) {
        throw new Q_Exception_RequiredField(array('field' => 'user'));
    }
    if (is_string($user)) {
        $userId = $user;
        $user = Users_User::fetch($userId);
        if (!$user) {
            throw new Q_Exception_MissingRow(array('table' => 'user', 'criteria' => "id={$userId}"));
        }
    }
    $ways = array();
    $email = $sms = $call = false;
    if (!empty($options['email']) and $user->emailAddress) {
        $email = is_string($options['email']) ? $options['email'] : "Email me";
        $email = Q_Html::img("plugins/Users/img/email.png") . $email;
        $ways['email'] = Q_Html::tag($tag, array('id' => 'email', 'class' => $class), $email);
        Q_Response::setToolOptions(array('emailAddress' => Q_Utils::obfuscate($user->emailAddress), 'emailSubject' => Q_Utils::obfuscate($emailSubject), 'emailBody' => Q_Utils::obfuscate($emailBody)));
    }
    if (Q_Request::isMobile()) {
        $obfuscated_mobileNumber = Q_Utils::obfuscate($user->mobileNumber);
        if (!empty($options['sms']) and $user->mobileNumber) {
            $sms = is_string($options['sms']) ? $options['sms'] : "Text me";
            $sms = Q_Html::img("plugins/Users/img/sms.png") . $sms;
            $ways['sms'] = Q_Html::tag($tag, array('id' => 'sms', 'class' => $class), $sms);
            Q_Response::setToolOptions(array('mobileNumber' => $obfuscated_mobileNumber));
        }
        if (!empty($options['call']) and $user->mobileNumber) {
            $call = is_string($options['call']) ? $options['call'] : "Call me";
            $call = Q_Html::img("plugins/Users/img/call.png") . $call;
            $ways['call'] = Q_Html::tag($tag, array('id' => 'call', 'class' => $class), $call);
            Q_Response::setToolOptions(array('mobileNumber' => $obfuscated_mobileNumber));
        }
    }
    return implode($between, $ways);
}
Esempio n. 29
0
/**
 * Makes a timestamp which is periodically updated.
 * Initially shows time offsets in '<some_time> ago' manner. Later represents time depending on format,
 * wisely excluding unnecessary detais (i.e. 'year' if timestamp has been made this year, 'year' and 'month if in this month etc).
 * @class Q timestamp
 * @constructor
 * @param {array} $options Options for the tool
 *	@param {integer} [$options.time=time()] Unix timestamp (in seconds), defaults to value of time() call.
 *	@param {string} [$options.format] formatting string which makes specific timestamp representation.
 *	 Can contain placeholders supported by strftime() and also few special placeholders with specific functionality.
 */
function Q_timestamp_tool($options)
{
    Q_Response::addScript('plugins/Q/js/tools/timestamp.js');
    Q_Response::addScript('plugins/Q/js/phpjs.js');
    $defaults = array('time' => time(), 'format' => '{day-week} {date+week} {year+year} %l:%M %P');
    $options = array_merge($defaults, $options);
    Q_Response::setToolOptions($options);
    @date_default_timezone_set(ini_get('date.timezone'));
    $format = $options['format'];
    $time = $options['time'];
    $now = time();
    $diff = $now - $time;
    $dayLength = 60 * 60 * 24;
    if ($diff > $dayLength) {
        return strftime($format, $time);
    } else {
        if ($diff > 3600 * 2) {
            return floor($diff / 3600) . ' hours ago';
        } else {
            if ($diff > 3600) {
                return '1 hour ago';
            } else {
                if ($diff > 60 * 2) {
                    return floor($diff / 60) . ' minutes ago';
                } else {
                    if ($diff > 60) {
                        return '1 minute ago';
                    } else {
                        if ($diff > 10) {
                            return $diff . ' seconds ago';
                        } else {
                            if ($diff > 0) {
                                return 'seconds ago';
                            } else {
                                return strftime($format, $time);
                            }
                        }
                    }
                }
            }
        }
    }
}
Esempio n. 30
0
/**
 * This tool generates an inline editor, along with a form tag.
 * @class Q inplace
 * @constructor
 * @param {array} [$options] An associative array of parameters, containing:
 *   @param {string} $options.fieldInput  Required. HTML representing a text input, textarea, or select.
 *   @param {string} $options.staticHtml  Required. The static HTML to display when the input isn't showing.
 *   @param {string} [$options.type='textarea']  The type of the input. Can be "textarea", "text" or "select"
 *   @param {string} [$options.action=""]  The uri or url to submit to
 *   @param {string} [$options.method="put"]  The method to use for submitting the form.
 *   @param {boolean} [$options.editing]  If true, then renders the inplace tool in editing mode.
 *   @param {boolean} [$options.editOnClick=true]  If true, then edit mode starts only if "Edit" button is clicked.
 *   @param {boolean} [$options.selectOnEdit=true] If true, selects all the text when entering edit mode.
 *   @param {string} [$options.placeholder] Text to show in the staticHtml or input field when the editor is empty
 *   @param {array} [$options.hidden] An associative array of additional hidden fields to submit in the form
 *   @param {integer} [$options.maxWidth] The maximum width for the Q/autogrow
 *   @param {string} [$options.beforeSave] Reference to a callback to call after a successful save. This callback can cancel the save by returning false.
 *   @param {string} [$options.onSave] Reference to a callback or event to run after a successful save.
 *   @param {string} [$options.onCancel] Reference to a callback or event to run after cancel.
 */
function Q_inplace_tool($options)
{
    $action = '';
    $method = 'put';
    $fieldInput = '';
    $staticHtml = '';
    $type = 'textarea';
    $editOnClick = true;
    $selectOnEdit = true;
    extract($options);
    if (isset($inplace)) {
        extract($inplace);
    }
    if (!isset($fieldInput)) {
        throw new Q_Exception_RequiredField(array('field' => 'fieldInput'));
    }
    $staticClass = $type === 'textarea' ? 'Q_inplace_tool_blockstatic' : 'Q_inplace_tool_static';
    Q_Response::addScript('plugins/Q/js/tools/inplace.js');
    Q_Response::addStylesheet('plugins/Q/css/inplace.css');
    $formTag = Q_Html::form("{$action}", $method, array('class' => 'Q_inplace_tool_form'));
    $hiddenInputs = $options['hidden'] ? Q_Html::hidden($options['hidden']) : '';
    $classes = !empty($editing) ? 'Q_editing Q_nocancel' : '';
    $options = compact('editOnClick', 'selectOnEdit', 'showEditButtons', 'maxWidth', 'beforeSave', 'onSave', 'placeholder', 'type');
    Q_Response::setToolOptions($options);
    $sh = $staticHtml ? $staticHtml : '<span class="Q_placeholder">' . Q_Html::text($placeholder) . '</span>';
    return <<<EOT
<div class='Q_inplace_tool_container {$classes} Q_inplace_{$type}' style="position: relative;">
\t<div class='Q_inplace_tool_editbuttons'>
\t\t<button class='Q_inplace_tool_edit basic16 basic16_edit'>Edit</button>
\t</div>
\t<div class='{$staticClass}'>{$sh}</div>
\t{$formTag}
\t\t{$fieldInput}
\t\t{$hiddenInputs}
\t\t<div class='Q_inplace_tool_buttons'>
\t\t\t<button class='Q_inplace_tool_cancel basic16 basic16_cancel'>Cancel</button>
\t\t\t<button class='Q_inplace_tool_save basic16 basic16_save'>Save</button>
\t\t</div>
\t</form>
</div>

EOT;
}